home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / think / MineSweeper2_7.lha / MineSweeper.mod < prev   
Text File  |  1994-03-08  |  97KB  |  3,158 lines

  1. MODULE MineSweeper;
  2.  
  3. (*
  4.    History:
  5.  
  6.  
  7.    v2.7  8 March 1994
  8.    ------------------
  9.    Fixed the bugs introduced in 2.6 :-)
  10.     * Mines can now be marked down the left column
  11.     * MututalExclude code in Static/Mobile sub menus fixed
  12.     * Documentation now up-to-date.
  13.     * Coloured numbers now working correctly (3.0 only function)
  14.  
  15.    v2.6  8 February 1994
  16.    ---------------------
  17.    Minor Bug Fix, option change.
  18.    Releasing RMB, in 'mark guess' mode over uncovered square, caused
  19.    garbage squares down left edge. (Ingimar Robertsson)
  20.    Made 'safe' behavior of guessed squares optional. (Ingimar Robertsson)
  21.    (Hopefully) Fixed bugs with colours not being freed on exit.
  22.  
  23.  
  24.    v2.5 13 December 1993
  25.    ---------------------
  26.    This is the first version of the source I am releasing for MineSweeper.
  27.  
  28.    I don't really recommend anyone try use more than snippets of this.
  29.    I feel safe you won't, as you would have to port it first ;-)
  30.    
  31.    Any comments you find in the code are likely to have been added just
  32.    prior to this release, and are likely to be minimal.
  33.    
  34.    I don't want any mail regarding any of this code!
  35.    
  36.    Bear in mind that much of the most messy bits of code could be
  37.    vastly improved if I removed the requirement for compatability
  38.    with 1.3, but at this point it's not worth it.
  39.    
  40.    13 December 1993
  41.    John Matthews
  42.    tribble@gphs.vuw.ac.nz
  43.  
  44. *)
  45.  
  46. IMPORT Intuition;
  47. IMPORT FastRandom;
  48. IMPORT Ports;
  49. IMPORT Text;
  50. IMPORT Pens;
  51. IMPORT Rasters;
  52. IMPORT Interrupts;
  53. IMPORT EasyText;
  54. IMPORT InputEvents;
  55. IMPORT Storage;
  56. IMPORT Graphics;
  57. IMPORT Blitter;
  58. IMPORT Memory;
  59. IMPORT BlitHardware;
  60. IMPORT Views;
  61. IMPORT EasyTimer;
  62. IMPORT Tasks;
  63. IMPORT TaskUtils;
  64. IMPORT DOS;
  65. IMPORT DOSProcess;
  66. IMPORT EasyMenus;
  67. IMPORT ImageTools;
  68. IMPORT Pointer;
  69. IMPORT RunTime;
  70. IMPORT ExecBase;
  71. IMPORT Console;
  72. IMPORT LinkedObjects;
  73. IMPORT Utility;
  74. FROM SYSTEM IMPORT
  75.     ADR, BYTE, ADDRESS, SHIFT, SETREG, REGISTER, STRPTR, LONG, CODE;
  76.  
  77.  
  78. FROM ChipData IMPORT
  79.     dataPtr;
  80.  
  81. CONST
  82.     ColoursID = 0636F6C73H;
  83.  
  84. TYPE
  85.     ColourNames = (* Attempted colours under V39 *)
  86.                       (* The actual values are linked in, but are just 96bit primaries *)
  87.     (    cnNull,
  88.         cnWhite,
  89.         cnBlue,
  90.         cnRed,
  91.         cnGreen,
  92.         cnYellow,
  93.         cnViolet,
  94.         cnPaleBlue,
  95.         cnBlack
  96.     );
  97.     ColourNameSet = SET OF ColourNames;
  98.     AColour =
  99.     RECORD
  100.         acR, acG, acB : LONGCARD;
  101.         (* Ala 3.0, FFFFFFFFH represents full strength component *)
  102.     END;
  103.     ColourArrayPtr = POINTER TO ColourArray;
  104.     ColourArray = ARRAY ColourNames OF AColour;
  105.     ColourInfoRecPtr = POINTER TO ColourInfoRec;
  106.     ColourInfoRec =
  107.     RECORD
  108.         id : LONGCARD;  (* This is just for linking purposes, my compiler is very old *)
  109.         cols : ColourArrayPtr;
  110.     END;
  111.  
  112.  
  113. TYPE
  114.     SkillLevel =
  115.     (    Beginner,
  116.         Intermediate,
  117.         Expert,
  118.         Custom
  119.     );
  120.     MenuVals =
  121.     (    mNewGame,
  122.         mBeginner,
  123.         mIntermediate,
  124.         mExpert,
  125.         mCustom,
  126.         mQuestions,
  127.         mCursor,
  128.         mSafe,
  129.         mScores,
  130.         mAbout,
  131.         mShrink,
  132.         mQuit);
  133.  
  134.     HA = (* for overloaded display/input window *)
  135.     (    modeAbout,
  136.         modeScores,
  137.         modeGetName,
  138.         modeGetCustom
  139.     );
  140.  
  141. CONST
  142.     HighScoreVersion = 3; (* For the highscore file *)
  143.     strID = 30;
  144.    InitLevel = Intermediate; (* Default if no highscore file *)
  145.  
  146.     (* Some string constants, let's keep them together *)
  147.     Version = "$VER: MineSweeper 2.7 (8.3.94)";
  148.     TaskName = "Sweep Seconds";
  149.     GameText = "Game";
  150.     GameTextLen = 4;
  151.     CompleteText = "Completion";
  152.     CompleteTextLen = 10;
  153.     MineSweeperName = "MineSweeper";
  154.     MaxStringLength = 30;
  155.     MineScores = "s:MineSweeper.highscores";
  156.    IntermediateString = "Intermediate";
  157.    BeginnerString = "Beginner";
  158.    ExpertString = "Expert";
  159.    CustomString = "Custom";
  160.     SquareFontName = "Courier.font";
  161.     SquareFontSize = 13;
  162.  
  163.     MinFieldWidth = 8;  (* Arbitrary *)
  164.     MinFieldHeight = 8;
  165.  
  166.     MaxFieldWidth = 32; (* NOT Arbitrary, 32bits per register! *)
  167.     MaxFieldHeight = 32;
  168.  
  169.     MinMines = 1;
  170.     MaxMines = 999;
  171.  
  172.     SquareWidth = 16;   (* blitting constants *)
  173.     SquareWidth3 = SquareWidth * 3;
  174.  
  175.     TopWindowArea = 32;
  176.  
  177.     NewGameID = 101; (* Gadget ID, not really used *)
  178.  
  179.     UnknownImage = 0; (* Image numbers, images are linked in *)
  180.     BlankImage = 1;
  181.     WonderImage = 2;
  182.     GuessImage = 3;
  183.     MineImage = 4;
  184.     FoundMineImage = 5;
  185.     BadGuessImage = 6;
  186.     SureImage = 7;
  187.     SmileyImage = 16;
  188.     AstonishedImage = 17;
  189.     UnhappyImage = 18;
  190.     SunGlassesImage = 19;
  191.     FirstImage = 0;
  192.     LastImage = 7;  (* Keep lower res images after 1:1 ones *)
  193.     FadePat = 20;
  194.     DigitOffset = 21; (* Numbers as images faster/smoother/less flicker than Text() *)
  195.     OneSecond = 1;
  196.     NoReStart = FALSE;
  197.     DoReStart = TRUE;
  198.  
  199.     MaxStackDepth = 256; (* Should be enough with Queue functions. Stack may need more *)
  200.  
  201.     CopyAtoD = Blitter.StraightCopy;
  202.  
  203.     NormalIDCMPs =
  204.        Intuition.IDCMPFlagSet{Intuition.GadgetDown,Intuition.GadgetUp,
  205.                               Intuition.MouseMove, Intuition.MenuPick,
  206.                               Intuition.CloseWindowFlag, Intuition.MouseButtons,
  207.                               Intuition.NewSize, Intuition.RefreshWindow,
  208.                               Intuition.RawKey
  209.                              };
  210.     WaitingIDCMPs =
  211.        Intuition.IDCMPFlagSet{Intuition.GadgetUp,
  212.                               Intuition.CloseWindowFlag, Intuition.MenuPick,
  213.                               Intuition.NewSize, Intuition.RefreshWindow,
  214.                               Intuition.RawKey
  215.                              };
  216.  
  217. TYPE
  218.     MovingStateType =
  219.     (    NoMove,
  220.         NormalMove,
  221.         SafeMove,
  222.         MineMove
  223.     );
  224.     MovingStateSet = SET OF MovingStateType;
  225.  
  226.     CompleteMethodType =
  227.     (    AllMinesFound,
  228.         AllNonMinesFound,
  229.         AllSquaresFound, (* Both   *)
  230.         EitherCompletion (* Either *)
  231.     );
  232.     FieldType =
  233.     (    fMines,
  234.         fCovered,
  235.         fGuessed,
  236.         fWondered
  237.     );
  238.  
  239.     MineFieldRow =
  240.     RECORD
  241.         Mines,
  242.         Covered,
  243.         Guessed,
  244.         Wondered : LONGBITSET;
  245.     END;
  246.     SquareState = (UnknownState, BlankState, WonderState, GuessState, MineState, FoundMineState, BadGuessState);
  247.     SquarePtr = POINTER TO SquareRecord;
  248.     SquareRecord =
  249.     RECORD
  250.       CASE : BOOLEAN OF
  251.         FALSE : l : LONGCARD
  252.       | TRUE  : xv,yv : INTEGER
  253.       END
  254.     END;
  255.     Score =
  256.     RECORD
  257.       NameLength : BYTE;
  258.       Pad : BYTE;
  259.       Seconds : CARDINAL;
  260.       Name : STRPTR;
  261.     END;
  262.     HighScoreRecordPtr = POINTER TO HighScoreRecord;
  263.     HighScoreRecord =
  264.     RECORD
  265.       InitX, InitY : INTEGER;
  266.       DefLevel : SkillLevel;
  267.       DefQuestions : BOOLEAN;
  268.       scores : ARRAY SkillLevel OF Score;
  269.     END;
  270.         FullStringGadPtr = POINTER TO FullStringGad;
  271.         FullStringGad =
  272.         RECORD
  273.           Gad : Intuition.Gadget;
  274.           SI : Intuition.StringInfo;
  275.           se : Intuition.StringExtend;
  276.           borders : ARRAY [0..1] OF Intuition.Border;
  277.           slines : ARRAY [0..9] OF LONGCARD;
  278.           fsBuffer, fsUndoBuffer : ARRAY [0..MaxStringLength] OF CHAR;
  279.         END;
  280.     SmallString = ARRAY [0..7] OF CHAR;
  281.     CustomRec =
  282.     RECORD
  283.       version : CARDINAL;
  284.       Width,Height,Mines : INTEGER;
  285.     END;
  286.  
  287. VAR
  288.     FieldWindow : Intuition.WindowPtr;
  289.     NewGameGad : Intuition.GadgetPtr;
  290.     ClipStore : ADDRESS;
  291.     FieldBM : Graphics.BitMapPtr;
  292.     ClipRPort,
  293.     FieldRPort : Rasters.RastPortPtr;
  294.     MainTask, TimerTask : Tasks.TaskPtr;
  295.     MainProcess : DOSProcess.ProcessPtr;
  296.     OLDprWindow : ADDRESS;
  297.     SquareFont : Text.TextFontPtr;
  298.     SquareFontAttr : Text.TextAttr;
  299.     SquareFontAttrPtr : Text.TextAttrPtr;
  300.     menu : Intuition.MenuPtr;
  301.     HighScores : HighScoreRecordPtr;
  302.     EntryGad : FullStringGadPtr;
  303.     SquareImages : ARRAY [FirstImage..LastImage] OF Intuition.ImagePtr;
  304.     CoveredRow : LONGBITSET;
  305.     FadePattern : ADDRESS;
  306.     CT : ADDRESS;
  307.     FaceImage : Intuition.ImagePtr;
  308.  
  309.     FieldRows : ARRAY [0..MaxFieldHeight - 1] OF MineFieldRow;
  310.     RealStackBuffer : ARRAY [0..MaxStackDepth - 1] OF SquareRecord;
  311.  
  312.   (* The comment identifiers Stack and Queue control how
  313.      MineSweeper looks around a square with no mines around it.
  314.      Queues are fastest, result in less depth, and a direct ripple
  315.      outwards.
  316.      Stacks look more interesting ;-)
  317.    *)
  318.  
  319. (*Stack+
  320.     StackBuffer : SquarePtr;
  321.     Stack : SquarePtr;
  322. *Stack-*)
  323.  
  324. (*Queue+*)
  325.     StackBuffer : POINTER TO ARRAY [0..MaxStackDepth - 1] OF SquareRecord;
  326.     StackIn, StackOut : CARDINAL;
  327. (*Queue-*)
  328.     
  329.     customrec : CustomRec;
  330.     
  331.     FieldWidth, FieldHeight, NumMines, MinesThisLevel, LastFieldWidth,
  332.     LastFieldHeight, LeftFieldBorder, TopFieldBorder, TopWindowBorder,
  333.     RightFieldBorder, FillParam : INTEGER;
  334.     FieldWindowWidth, FieldWindowHeight, RightWindowBorder, BottomWindowBorder,
  335.     LeftTextBorder, RightTextBorder, TopTextBorder, TextWidth, TextHeight,
  336.     LeftSquareText, TopSquareText, SquareHeight, SquareHeight3, LastSquareCount,
  337.     GuessedMines, GuessedRightMines : INTEGER;
  338.     QuitNow, WaitingForNew, V36Colours,
  339.     TimerError, FirstHit, TimerIsGoing, Restarting,
  340.     V36, Questions, Laced, Shrunk, WindowSized,
  341.     FromMouse, MovingAllowed, SafeIfMarked : BOOLEAN;
  342.     CompleteMethod : CompleteMethodType;
  343.     Lastx, Lasty, Lastxp, Lastyp : INTEGER;
  344.     ClipBM : Graphics.BitMap;
  345.     MovingState, LastState : MovingStateType;
  346.     Pen1,Pen2 : CARDINAL;
  347.     ClipTempRas : Rasters.TmpRas;
  348.     TimerAckBit, CountBit, StartBit, StopBit, WindowBit : Tasks.SIGNAL;
  349.     WaitBits, TimerAcks : Tasks.SignalSet;
  350.     NonMinesCovered,Seconds, NewHigh : CARDINAL;
  351.     Level : SkillLevel;
  352.     SmileX, SmileY : CARDINAL;
  353.     ObtainedPens : ColourNameSet;
  354.     ColourPens : ARRAY ColourNames OF CARDINAL;
  355.     
  356.     ChunkyBuf : ARRAY [0..31] OF SquareState;
  357.  
  358. (*StackCheck+
  359.     StackDepth, StackDepthReached : CARDINAL;
  360. *StackCheck-*)
  361.  
  362.  
  363.  
  364. PROCEDURE FlashDisplay(num : CARDINAL);
  365. BEGIN
  366.   WHILE num > 0 DO
  367.     DEC(num);
  368.     Views.WaitTOF;
  369.     Blitter.ClipBlit(
  370.        FieldRPort,LeftFieldBorder,TopFieldBorder,
  371.        FieldRPort,LeftFieldBorder,TopFieldBorder,
  372.        FieldWindowWidth, FieldWindowHeight,
  373.        BYTE(48)
  374.     );
  375.     Views.WaitTOF;
  376.   END;
  377. END FlashDisplay;
  378.  
  379. PROCEDURE TestGameOver(); FORWARD;
  380.  
  381. PROCEDURE RefreshDisplay(refresh : BOOLEAN); FORWARD;
  382.  
  383. PROCEDURE DoFill(rp : Rasters.RastPortPtr; pt : ADDRESS; ph : INTEGER; pen,l,t,r,b : CARDINAL);
  384. BEGIN
  385.   IF RunTime.ExecVersion < 39 THEN
  386.     Pens.SetDrMd(rp,Rasters.Jam2);
  387.     Pens.SetAPen(rp,pen);
  388.     Pens.SetBPen(rp,0);
  389.   ELSE
  390.     Pens.SetABPenDrMd(rp,pen,0,Rasters.Jam2)
  391.   END;
  392.   Pens.SetAfPat(rp,pt,ph);
  393.   Blitter.BltPattern(rp,NIL,l,t,r,b,2);
  394. END DoFill;
  395.  
  396.  
  397. (*$LONG_ADDR+*)
  398. PROCEDURE ConvNum(VAR str : ARRAY OF CHAR; v : INTEGER);
  399. VAR
  400.     sp : POINTER TO CHAR;
  401.     t : INTEGER;
  402.     n : BOOLEAN;
  403.  
  404.   PROCEDURE AddDigit(d : INTEGER);
  405.   BEGIN
  406.     sp^ := CHR(ORD('0') + d);;
  407.     INC(sp);
  408.   END AddDigit;
  409.   
  410.  
  411. BEGIN
  412.   sp := ADR(str);
  413.   n := v < 0;
  414.   v := ABS(v);
  415.   t := v DIV 1000;
  416.   DEC(v,t * 1000);
  417.   IF n THEN
  418.     sp^ := '-';
  419.     INC(sp);
  420.   ELSE
  421.     AddDigit(t);
  422.   END;
  423.   t := v DIV 100;
  424.   DEC(v,t * 100);
  425.   AddDigit(t);
  426.   t := v DIV 10;
  427.   DEC(v,t * 10);
  428.   AddDigit(t);
  429.   AddDigit(v);
  430.   sp^ := 0C
  431. END ConvNum;
  432. (*$LONG_ADDR-*)
  433.  
  434. PROCEDURE WriteNum(v : INTEGER; x,y : CARDINAL);
  435. VAR
  436.     t : INTEGER;
  437.     n : BOOLEAN;
  438.  
  439.   PROCEDURE AddDigit(d : INTEGER);
  440.   BEGIN
  441.     Intuition.DrawImage(FieldRPort,dataPtr^.Images[DigitOffset + d],x,y);
  442.     INC(x,10);
  443.   END AddDigit;
  444.   
  445.  
  446. BEGIN
  447.   n := v < 0;
  448.   v := ABS(v);
  449.   t := v DIV 1000;
  450.   DEC(v,t * 1000);
  451.   IF n THEN
  452.     t := 10; (* negative digit *)
  453.   END;
  454.   AddDigit(t);
  455.   t := v DIV 100;
  456.   DEC(v,t * 100);
  457.   AddDigit(t);
  458.   t := v DIV 10;
  459.   DEC(v,t * 10);
  460.   AddDigit(t);
  461.   AddDigit(v);
  462. END WriteNum;
  463.  
  464. PROCEDURE SetSize(l : SkillLevel);
  465. BEGIN
  466.   Level := l;
  467.   CASE l OF
  468.      Beginner :
  469.        FieldWidth := 8;
  470.        FieldHeight := 8;
  471.        MinesThisLevel := 10;
  472.    | Intermediate :
  473.        FieldWidth := 16;
  474.        FieldHeight := 16;
  475.        MinesThisLevel := 40;
  476.    | Expert :
  477.        FieldWidth := 32;
  478.        FieldHeight := 16;
  479.        MinesThisLevel := 99;
  480.    | Custom :
  481.        WITH customrec DO
  482.          FieldWidth := Width;
  483.          FieldHeight := Height;
  484.          MinesThisLevel := Mines;
  485.        END; 
  486.   END
  487. END SetSize;
  488.  
  489.  
  490. PROCEDURE UpdateMineCountDisplay();
  491. VAR
  492.     Unfound : INTEGER;
  493.     str : SmallString;
  494. BEGIN
  495.   Unfound := NumMines - GuessedMines;
  496.   WriteNum(Unfound,LeftTextBorder, TopTextBorder);
  497. END UpdateMineCountDisplay;
  498.  
  499. PROCEDURE UpdateTime();
  500. VAR
  501.     str : SmallString;
  502. BEGIN
  503.   WriteNum(Seconds,RightTextBorder, TopTextBorder);
  504. END UpdateTime;
  505.  
  506. PROCEDURE TimerProc();
  507. VAR
  508.     WaitSigs, GotSigs : Tasks.SignalSet;
  509.     Counting : BOOLEAN;
  510.  
  511.   PROCEDURE TimerExit();
  512.   BEGIN
  513.     Interrupts.Forbid;
  514.     TimerIsGoing := FALSE;
  515.     IF StartBit # Tasks.NoSignals THEN
  516.       Tasks.FreeSignal(StartBit)
  517.     END;
  518.     IF StopBit # Tasks.NoSignals THEN
  519.       Tasks.FreeSignal(StopBit)
  520.     END;
  521.     EasyTimer.DeleteTimer;
  522.     Tasks.Signal(MainTask,TimerAcks);
  523.     TaskUtils.DeleteTask(TimerTask);
  524.   END TimerExit;
  525.   
  526.  
  527. BEGIN
  528.   Counting := FALSE;
  529.   StartBit := Tasks.AllocSignal(Tasks.AnySignal);
  530.   StopBit := Tasks.AllocSignal(Tasks.AnySignal);
  531.   IF (StartBit = Tasks.NoSignals) OR (StopBit = Tasks.NoSignals)
  532.     OR ~EasyTimer.CreateTimer() THEN
  533.     TimerError := TRUE;
  534.     TimerExit;
  535.   END;
  536.   Tasks.Signal(MainTask,TimerAcks);
  537.   TimerIsGoing := TRUE;
  538.   WaitSigs := Tasks.SignalSet{CARDINAL(EasyTimer.TimerBit),CARDINAL(StartBit),CARDINAL(StopBit)};
  539.   LOOP
  540.     GotSigs := Tasks.Wait(WaitSigs);
  541.     IF CARDINAL(StartBit) IN GotSigs THEN
  542.       EasyTimer.SendTimeDelay(OneSecond);
  543.       Counting := TRUE;
  544.       Tasks.Signal(MainTask,TimerAcks);
  545.     END;
  546.     IF CARDINAL(EasyTimer.TimerBit) IN GotSigs THEN
  547.       EasyTimer.TimerAck;
  548.       IF Counting THEN
  549.         EasyTimer.SendTimeDelay(OneSecond);
  550.         IF (Seconds < 9999) THEN
  551.           INC(Seconds)
  552.         END;
  553.         Tasks.Signal(MainTask,Tasks.SignalSet{CARDINAL(CountBit)});
  554.       END;
  555.     END;
  556.     IF CARDINAL(StopBit) IN GotSigs THEN
  557.       Counting := FALSE;
  558.       IF QuitNow THEN
  559.         TimerExit;
  560.       ELSE
  561.         Tasks.Signal(MainTask,TimerAcks);
  562.       END
  563.     END;
  564.   END
  565. END TimerProc;
  566.  
  567. PROCEDURE StartTimer();
  568. VAR
  569.     sigs : Tasks.SignalSet;
  570. BEGIN
  571.   Tasks.Signal(TimerTask,Tasks.SignalSet{CARDINAL(StartBit)});
  572.   sigs := Tasks.Wait(TimerAcks);
  573.   UpdateTime;
  574. END StartTimer;
  575.  
  576. PROCEDURE StopTimer();
  577. VAR
  578.     sigs : Tasks.SignalSet;
  579. BEGIN
  580.   IF TimerIsGoing THEN
  581.     Tasks.Signal(TimerTask,Tasks.SignalSet{CARDINAL(StopBit)});
  582.     sigs := Tasks.Wait(TimerAcks);
  583.   END;
  584. END StopTimer;
  585.  
  586. PROCEDURE EndGame(StartNew : BOOLEAN);
  587. BEGIN
  588.   StopTimer;
  589.   IF ~StartNew THEN
  590.     Intuition.ModifyIDCMP(FieldWindow,WaitingIDCMPs);
  591.     FieldWindow^.Flags :=
  592.          FieldWindow^.Flags
  593.        - Intuition.WindowFlagSet{Intuition.RMBTrap,Intuition.ReportMouseFlag};
  594.     WaitingForNew := TRUE;
  595.     MovingState := NoMove;
  596.   END;
  597.   RETURN
  598. END EndGame;
  599.  
  600. PROCEDURE GetPens(cm : Views.ColorMapPtr);
  601. VAR
  602.     tags : ARRAY [0..1] OF Utility.TagItem;
  603.     res : LONGINT;
  604.     cir : ColourInfoRecPtr;
  605.     i : ColourNames;
  606. BEGIN
  607.   IF ObtainedPens # ColourNameSet{} THEN
  608.     RETURN
  609.   END;
  610.   tags[0].tiTag := Pens.OBP_Precision;
  611.   tags[0].tiData := Pens.Precision_Image;
  612.   tags[1].tiTag := Utility.TAGDone;
  613.   cir := LinkedObjects.FindObject(ColoursID);
  614.   IF (RunTime.ExecVersion < 39) OR (cir = NIL) THEN
  615.     FOR i := MIN(ColourNames) TO MAX(ColourNames) DO
  616.       ColourPens[i] := Pen2;
  617.     END
  618.   ELSE
  619.     cm := FieldWindow^.WScreen^.VPort.ColorMap;
  620.     i := MIN(ColourNames);
  621.     LOOP
  622.       INC(i);
  623.       WITH cir^.cols^[i] DO
  624.         res := Pens.ObtainBestPen(cm,acR,acG,acB,ADR(tags));
  625.         IF res >= 0 THEN
  626.           ColourPens[i] := CARDINAL(res);
  627.           INCL(ObtainedPens,i);
  628.           
  629.         END;
  630.       END;
  631.       IF i = MAX(ColourNames) THEN
  632.         EXIT
  633.       END;
  634.     END
  635.   END;
  636. END GetPens;
  637.  
  638.  
  639. PROCEDURE FindColourScheme;
  640. VAR
  641.   CM : Views.ColorMapPtr;
  642.  
  643.   PROCEDURE Intensity(Entry : LONGINT) : INTEGER;
  644.   VAR
  645.     temp, result, i : INTEGER;
  646.   BEGIN
  647.     result := 1;
  648.     temp := Views.GetRGB4(CM,Entry);
  649.     FOR i := 0 TO 2 DO
  650.       result := result * INTEGER(BITSET(temp) * BITSET{0..3});
  651.       temp := SHIFT(temp,-4);
  652.     END;
  653.     RETURN result
  654.   END Intensity;
  655.   
  656. VAR
  657.   dummy : LONGCARD;
  658.   i : CARDINAL;
  659. BEGIN
  660.   CM := FieldWindow^.WScreen^.VPort.ColorMap;
  661.   GetPens(CM);
  662.   V36Colours := (Intensity(2) > Intensity(1));
  663.   IF V36Colours THEN
  664.     Pen1 := 1;
  665.     Pen2 := 2;
  666.   ELSE
  667.     i := 0;
  668.     WHILE i < CARDINAL(dataPtr^.NumImages) DO
  669.       ImageTools.ReversePlanes(dataPtr^.Images[i]);
  670.       INC(i)
  671.     END;
  672.     Pen2 := 1;
  673.     Pen1 := 2;
  674.   END;
  675. END FindColourScheme;
  676.  
  677.  
  678. PROCEDURE InitClip(d:CARDINAL) : BOOLEAN;
  679. VAR
  680.     rs,frs : LONGCARD;
  681.     w,h : CARDINAL;
  682. BEGIN
  683.   w := SquareWidth3;
  684.   h := SquareHeight3;
  685.   rs := Graphics.RASSIZE(w,h);
  686.   frs := rs * LONGCARD(d);
  687.   ClipStore := Storage.TrackAllocMem(frs,Memory.MemReqSet{Memory.MemChip});
  688.   IF ClipStore = NIL THEN RETURN FALSE END;
  689.   Storage.ALLOCATE(ClipRPort,SIZE(ClipRPort^));
  690.   IF ClipRPort = NIL THEN RETURN FALSE END;
  691.   Rasters.InitRastPort(ClipRPort);
  692.   ClipRPort^.BitMap := ADR(ClipBM);
  693.   Rasters.InitTmpRas(ADR(ClipTempRas),Storage.TrackAllocMem(frs,Memory.MemReqSet{Memory.MemChip}),frs);
  694.   ClipRPort^.TmpRas := ADR(ClipTempRas);
  695.   frs := LONGCARD(ClipStore);
  696.   Graphics.InitBitMap(ADR(ClipBM),d,w,h);
  697.   WITH ClipBM DO
  698.     w := 0;
  699.     WHILE w < d DO
  700.       Planes[w] := ADDRESS(frs);
  701.       INC(frs,rs);
  702.       INC(w);
  703.     END
  704.   END;
  705. END InitClip;
  706.  
  707.  
  708.  
  709.  
  710.  
  711. PROCEDURE PushStack(xi,yi : INTEGER);
  712. BEGIN
  713.   IF (CARDINAL(xi) < CARDINAL(FieldWidth)) & (CARDINAL(yi) < CARDINAL(FieldHeight)) THEN
  714.     WITH FieldRows[yi] DO
  715.       IF (CARDINAL(xi) IN Covered) & ~(CARDINAL(xi) IN Guessed) THEN
  716.         EXCL(Covered,CARDINAL(xi));
  717. (*Queue+*)
  718.         WITH StackBuffer^[StackIn] DO
  719.           xv := xi;
  720.           yv := yi;
  721.         END;
  722.         StackIn := (StackIn + 1) MOD MaxStackDepth;
  723. (*Queue-*)
  724. (*Stack+
  725.         Stack^.l := LONG(xi,yi);
  726.         INC(Stack,4);
  727. *Stack-*)
  728. (*StackCheck+
  729.         INC(StackDepth);
  730.         IF StackDepth >= MaxStackDepth THEN
  731.           TermOut.WriteString("Stack Depth Exceeded\n");
  732.         END;
  733.         IF StackDepth >= StackDepthReached THEN
  734.           StackDepthReached := StackDepth
  735.         END;
  736. *StackCheck-*)
  737.       END;
  738.     END
  739.   END
  740. END PushStack;
  741.  
  742. (***LookAsm+*)
  743. (*$LONG_ADDR+*)
  744. PROCEDURE LookAround(xi,yi : INTEGER);
  745. BEGIN
  746. (*Queue+*)
  747.     SETREG(0,yi);
  748.     SETREG(1,xi);
  749.     SETREG(2,FieldWidth);
  750.     SETREG(3,FieldHeight);
  751.     SETREG(4,MaxStackDepth);
  752.     SETREG(8,ADR(FieldRows));
  753.     SETREG(9,StackBuffer);
  754.     SETREG(10,ADR(StackIn));
  755. (*     1 0000:                          ;d0 - y*)
  756. (*     2 0000:                          ;d1 - x*)
  757. (*     3 0000:                          ;d2 - FieldWidth*)
  758. (*     4 0000:                          ;d3 - FieldHeight*)
  759. (*     5 0000:                          ;d4 - MaxStackDepth*)
  760. (*     6 0000:                          ;a0 - FieldRows*)
  761. (*     7 0000:                          ;a1 - Stack*)
  762. (*     8 0000:                          ;a2 - ADR(StackIn)*)
  763. (*     9 0000:*)  CODE(05341H);(*                    subq.w #1,d1    ; start left*)
  764. (*    10 0002:*)  CODE(05340H);(*                    subq.w #1,d0    ; top*)
  765. (*    11 0004:*)  CODE(03a00H);(*                    move.w d0,d5    ; initial offset into FieldRows*)
  766. (*    12 0006:*)  CODE(0e945H);(*                    asl.w #4,d5        ; 16 bytes per block *)
  767. (*    13 0008:*)  CODE(0d0c5H);(*                    adda.w d5,a0    ; add it IN*)
  768. (*    14 000a:*)  CODE(0b043H);(*                    cmp.w d3,d0        ; neg y ?*)
  769. (*    15 000c:*)  CODE(06438H);(*                    bcc row2            ; skip first row*)
  770. (*    16 000e:*)  CODE(02a28H,00008H);(*             move.l 8(a0),d5; Guessed*)
  771. (*    17 0012:*)  CODE(04685H);(*                    NOT.l d5            ; ~Guessed*)
  772. (*    18 0014:*)  CODE(02c28H,00004H);(*             move.l 4(a0),d6; Covered for this row*)
  773. (*    19 0018:*)  CODE(0ca86H);(*                    AND.l d6,d5        ; only do if covered & ~guessed*)
  774. (*    20 001a:*)  CODE(0b242H);(*                    cmp.w d2,d1        ; x neg ?*)
  775. (*    21 001c:*)  CODE(06408H);(*                    bcc c12            ; skip col*)
  776. (*    22 001e:*)  CODE(00305H);(*                    btst.l d1,d5    ; check square conditions*)
  777. (*    23 0020:*)  CODE(06704H);(*                    beq c12            ; failed, skip*)
  778. (*    24 0022:*)  CODE(06100H,00092H);(*             bsr.s nq            ; passed, enqueue*)
  779. (*    25 0026:*)  CODE(05241H);(*              c12:  addq.w #1,d1    ; next col*)
  780. (*    26 0028:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  781. (*    27 002a:*)  CODE(06408H);(*                    bcc c13*)
  782. (*    28 002c:*)  CODE(00305H);(*                    btst.l d1,d5*)
  783. (*    29 002e:*)  CODE(06704H);(*                    beq c13*)
  784. (*    30 0030:*)  CODE(06100H,00084H);(*             bsr.s nq*)
  785. (*    31 0034:*)  CODE(05241H);(*              c13:  addq.w #1,d1*)
  786. (*    32 0036:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  787. (*    33 0038:*)  CODE(06406H);(*                    bcc c1e*)
  788. (*    34 003a:*)  CODE(00305H);(*                    btst.l d1,d5*)
  789. (*    35 003c:*)  CODE(06702H);(*                    beq c1e*)
  790. (*    36 003e:*)  CODE(06176H);(*                    bsr.s nq*)
  791. (*    37 0040:*)  CODE(05541H);(*              c1e:  subq.w #2,d1*)
  792. (*    38 0042:*)  CODE(02146H,00004H);(*             move.l d6,4(a0); save Covered for this row*)
  793. (*    39 0046:*)  CODE(05088H);(*              row2: addq.l #8,a0*)
  794. (*    40 0048:*)  CODE(05088H);(*                    addq.l #8,a0*)
  795. (*    41 004a:*)  CODE(05240H);(*                    addq.w #1,d0*)
  796. (*    42 004c:*)  CODE(0b043H);(*                    cmp.w d3,d0*)
  797. (*    43 004e:*)  CODE(06428H);(*                    bcc row3*)
  798. (*    44 0050:*)  CODE(02a28H,00008H);(*             move.l 8(a0),d5*)
  799. (*    45 0054:*)  CODE(04685H);(*                    NOT.l d5*)
  800. (*    46 0056:*)  CODE(02c28H,00004H);(*             move.l 4(a0),d6*)
  801. (*    47 005a:*)  CODE(0ca86H);(*                    AND.l d6,d5*)
  802. (*    48 005c:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  803. (*    49 005e:*)  CODE(06406H);(*                    bcc c23*)
  804. (*    50 0060:*)  CODE(00305H);(*                    btst.l d1,d5*)
  805. (*    51 0062:*)  CODE(06702H);(*                    beq c23*)
  806. (*    52 0064:*)  CODE(06150H);(*                    bsr.s nq*)
  807. (*    53 0066:*)  CODE(05441H);(*              c23:  addq.w #2,d1*)
  808. (*    54 0068:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  809. (*    55 006a:*)  CODE(06406H);(*                    bcc c2e*)
  810. (*    56 006c:*)  CODE(00305H);(*                    btst.l d1,d5*)
  811. (*    57 006e:*)  CODE(06702H);(*                    beq c2e*)
  812. (*    58 0070:*)  CODE(06144H);(*                    bsr.s nq*)
  813. (*    59 0072:*)  CODE(05541H);(*              c2e:  subq.w #2,d1*)
  814. (*    60 0074:*)  CODE(02146H,00004H);(*             move.l d6,4(a0)*)
  815. (*    61 0078:*)  CODE(05240H);(*              row3: addq.w #1,d0*)
  816. (*    62 007a:*)  CODE(0b043H);(*                    cmp.w d3,d0*)
  817. (*    63 007c:*)  CODE(06452H);(*                    bcc fin*)
  818. (*    64 007e:*)  CODE(05088H);(*                    addq.l #8,a0*)
  819. (*    65 0080:*)  CODE(05088H);(*                    addq.l #8,a0*)
  820. (*    66 0082:*)  CODE(02a28H,00008H);(*             move.l 8(a0),d5*)
  821. (*    67 0086:*)  CODE(04685H);(*                    NOT.l d5*)
  822. (*    68 0088:*)  CODE(02c28H,00004H);(*             move.l 4(a0),d6*)
  823. (*    69 008c:*)  CODE(0ca86H);(*                    AND.l d6,d5*)
  824. (*    70 008e:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  825. (*    71 0090:*)  CODE(06406H);(*                    bcc c32*)
  826. (*    72 0092:*)  CODE(00305H);(*                    btst.l d1,d5*)
  827. (*    73 0094:*)  CODE(06702H);(*                    beq c32*)
  828. (*    74 0096:*)  CODE(0611eH);(*                    bsr.s nq*)
  829. (*    75 0098:*)  CODE(05241H);(*              c32:  addq.w #1,d1*)
  830. (*    76 009a:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  831. (*    77 009c:*)  CODE(06406H);(*                    bcc c33*)
  832. (*    78 009e:*)  CODE(00305H);(*                    btst.l d1,d5*)
  833. (*    79 00a0:*)  CODE(06702H);(*                    beq c33*)
  834. (*    80 00a2:*)  CODE(06112H);(*                    bsr.s nq*)
  835. (*    81 00a4:*)  CODE(05241H);(*              c33:  addq.w #1,d1*)
  836. (*    82 00a6:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  837. (*    83 00a8:*)  CODE(06406H);(*                    bcc c3e*)
  838. (*    84 00aa:*)  CODE(00305H);(*                    btst.l d1,d5*)
  839. (*    85 00ac:*)  CODE(06702H);(*                    beq c3e*)
  840. (*    86 00ae:*)  CODE(06106H);(*                    bsr.s nq*)
  841. (*    87 00b0:*)  CODE(02146H,00004H);(*       c3e:  move.l d6,4(a0)*)
  842. (*    88 00b4:*)  CODE(0601aH);(*                      bra.s fin*)
  843. (*    89 00b6:*)  CODE(03e12H);(*              nq:    move.w (a2),d7    ; queue index*)
  844. (*    90 00b8:*)  CODE(0e547H);(*                      asl.w #2,d7        ; scale for longwords*)
  845. (*    91 00ba:*)  CODE(047f1H,07000H);(*               lea.l 0(a1,d7.w),a3 ; get pos*)
  846. (*    92 00be:*)  CODE(036c1H);(*                      move.w d1,(a3)+    ; save x*)
  847. (*    93 00c0:*)  CODE(03680H);(*                      move.w d0,(a3)        ; save y*)
  848. (*    94 00c2:*)  CODE(00386H);(*                    bclr.l d1,d6        ; uncover square*)
  849. (*    95 00c4:*)  CODE(05252H);(*                      addq.w #1,(a2)        ; inc stack pos*)
  850. (*    96 00c6:*)  CODE(0b852H);(*                      cmp.w (a2),d4        ; wrap ?*)
  851. (*    97 00c8:*)  CODE(06702H);(*                      beq.s wrap*)
  852. (*    98 00ca:*)  CODE(04e75H);(*                      rts*)
  853. (*    99 00cc:*)  CODE(04252H);(*              wrap:    clr.w (a2)*)
  854. (*   100 00ce:*)  CODE(04e75H);(*                      rts*)
  855. (*   101 00d0:*)  CODE(04e71H);(*              fin:  nop*)
  856. (*Queue-*)
  857. (*Stack+
  858.     SETREG(0,yi);
  859.     SETREG(1,xi);
  860.     SETREG(2,FieldWidth);
  861.     SETREG(3,FieldHeight);
  862.     SETREG(8,ADR(FieldRows));
  863.     SETREG(10,ADR(Stack));
  864. (*     1 0000:                          ;d0 - y*)
  865. (*     2 0000:                          ;d1 - x*)
  866. (*     3 0000:                          ;d2 - FieldWidth*)
  867. (*     4 0000:                          ;d3 - FieldHeight*)
  868. (*     5 0000:                          ;a0 - FieldRows*)
  869. (*     6 0000:                          ;a1 - Stack*)
  870. (*     7 0000:                          ;a2 - ADR(Stack)*)
  871. (*     8 0000:*)  CODE(02252H);(*                    move.l (a2),a1*)
  872. (*     9 0002:*)  CODE(05341H);(*                    subq.w #1,d1*)
  873. (*    10 0004:*)  CODE(05340H);(*                    subq.w #1,d0*)
  874. (*    11 0006:*)  CODE(03800H);(*                    move.w d0,d4*)
  875. (*    12 0008:*)  CODE(0e944H);(*                    asl.w #4,d4*)
  876. (*    13 000a:*)  CODE(0d0c4H);(*                    adda.w d4,a0*)
  877. (*    14 000c:*)  CODE(0b043H);(*                    cmp.w d3,d0*)
  878. (*    15 000e:*)  CODE(06440H);(*                    bcc row2*)
  879. (*    16 0010:*)  CODE(02a28H,00008H);(*             move.l 8(a0),d5*)
  880. (*    17 0014:*)  CODE(04685H);(*                    NOT.l d5*)
  881. (*    18 0016:*)  CODE(02c28H,00004H);(*             move.l 4(a0),d6*)
  882. (*    19 001a:*)  CODE(0ca86H);(*                    AND.l d6,d5*)
  883. (*    20 001c:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  884. (*    21 001e:*)  CODE(0640aH);(*                    bcc c12*)
  885. (*    22 0020:*)  CODE(00305H);(*                    btst.l d1,d5*)
  886. (*    23 0022:*)  CODE(06706H);(*                    beq c12*)
  887. (*    24 0024:*)  CODE(032c1H);(*                    move.w d1,(a1)+*)
  888. (*    25 0026:*)  CODE(032c0H);(*                    move.w d0,(a1)+*)
  889. (*    26 0028:*)  CODE(00386H);(*                    bclr.l d1,d6*)
  890. (*    27 002a:*)  CODE(05241H);(*              c12:  addq.w #1,d1*)
  891. (*    28 002c:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  892. (*    29 002e:*)  CODE(0640aH);(*                    bcc c13*)
  893. (*    30 0030:*)  CODE(00305H);(*                    btst.l d1,d5*)
  894. (*    31 0032:*)  CODE(06706H);(*                    beq c13*)
  895. (*    32 0034:*)  CODE(032c1H);(*                    move.w d1,(a1)+*)
  896. (*    33 0036:*)  CODE(032c0H);(*                    move.w d0,(a1)+*)
  897. (*    34 0038:*)  CODE(00386H);(*                    bclr.l d1,d6*)
  898. (*    35 003a:*)  CODE(05241H);(*              c13:  addq.w #1,d1*)
  899. (*    36 003c:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  900. (*    37 003e:*)  CODE(0640aH);(*                    bcc c1e*)
  901. (*    38 0040:*)  CODE(00305H);(*                    btst.l d1,d5*)
  902. (*    39 0042:*)  CODE(06706H);(*                    beq c1e*)
  903. (*    40 0044:*)  CODE(032c1H);(*                    move.w d1,(a1)+*)
  904. (*    41 0046:*)  CODE(032c0H);(*                    move.w d0,(a1)+*)
  905. (*    42 0048:*)  CODE(00386H);(*                    bclr.l d1,d6*)
  906. (*    43 004a:*)  CODE(05541H);(*              c1e:  subq.w #2,d1*)
  907. (*    44 004c:*)  CODE(02146H,00004H);(*             move.l d6,4(a0)*)
  908. (*    45 0050:*)  CODE(05088H);(*              row2: addq.l #8,a0*)
  909. (*    46 0052:*)  CODE(05088H);(*                    addq.l #8,a0*)
  910. (*    47 0054:*)  CODE(05240H);(*                    addq.w #1,d0*)
  911. (*    48 0056:*)  CODE(0b043H);(*                    cmp.w d3,d0*)
  912. (*    49 0058:*)  CODE(06430H);(*                    bcc row3*)
  913. (*    50 005a:*)  CODE(02a28H,00008H);(*             move.l 8(a0),d5*)
  914. (*    51 005e:*)  CODE(04685H);(*                    NOT.l d5*)
  915. (*    52 0060:*)  CODE(02c28H,00004H);(*             move.l 4(a0),d6*)
  916. (*    53 0064:*)  CODE(0ca86H);(*                    AND.l d6,d5*)
  917. (*    54 0066:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  918. (*    55 0068:*)  CODE(0640aH);(*                    bcc c23*)
  919. (*    56 006a:*)  CODE(00305H);(*                    btst.l d1,d5*)
  920. (*    57 006c:*)  CODE(06706H);(*                    beq c23*)
  921. (*    58 006e:*)  CODE(032c1H);(*                    move.w d1,(a1)+*)
  922. (*    59 0070:*)  CODE(032c0H);(*                    move.w d0,(a1)+*)
  923. (*    60 0072:*)  CODE(00386H);(*                    bclr.l d1,d6*)
  924. (*    61 0074:*)  CODE(05441H);(*              c23:  addq.w #2,d1*)
  925. (*    62 0076:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  926. (*    63 0078:*)  CODE(0640aH);(*                    bcc c2e*)
  927. (*    64 007a:*)  CODE(00305H);(*                    btst.l d1,d5*)
  928. (*    65 007c:*)  CODE(06706H);(*                    beq c2e*)
  929. (*    66 007e:*)  CODE(032c1H);(*                    move.w d1,(a1)+*)
  930. (*    67 0080:*)  CODE(032c0H);(*                    move.w d0,(a1)+*)
  931. (*    68 0082:*)  CODE(00386H);(*                    bclr.l d1,d6*)
  932. (*    69 0084:*)  CODE(05541H);(*              c2e:  subq.w #2,d1*)
  933. (*    70 0086:*)  CODE(02146H,00004H);(*             move.l d6,4(a0)*)
  934. (*    71 008a:*)  CODE(05240H);(*              row3: addq.w #1,d0*)
  935. (*    72 008c:*)  CODE(0b043H);(*                    cmp.w d3,d0*)
  936. (*    73 008e:*)  CODE(06442H);(*                    bcc fin*)
  937. (*    74 0090:*)  CODE(05088H);(*                    addq.l #8,a0*)
  938. (*    75 0092:*)  CODE(05088H);(*                    addq.l #8,a0*)
  939. (*    76 0094:*)  CODE(02a28H,00008H);(*             move.l 8(a0),d5*)
  940. (*    77 0098:*)  CODE(04685H);(*                    NOT.l d5*)
  941. (*    78 009a:*)  CODE(02c28H,00004H);(*             move.l 4(a0),d6*)
  942. (*    79 009e:*)  CODE(0ca86H);(*                    AND.l d6,d5*)
  943. (*    80 00a0:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  944. (*    81 00a2:*)  CODE(0640aH);(*                    bcc c32*)
  945. (*    82 00a4:*)  CODE(00305H);(*                    btst.l d1,d5*)
  946. (*    83 00a6:*)  CODE(06706H);(*                    beq c32*)
  947. (*    84 00a8:*)  CODE(032c1H);(*                    move.w d1,(a1)+*)
  948. (*    85 00aa:*)  CODE(032c0H);(*                    move.w d0,(a1)+*)
  949. (*    86 00ac:*)  CODE(00386H);(*                    bclr.l d1,d6*)
  950. (*    87 00ae:*)  CODE(05241H);(*              c32:  addq.w #1,d1*)
  951. (*    88 00b0:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  952. (*    89 00b2:*)  CODE(0640aH);(*                    bcc c33*)
  953. (*    90 00b4:*)  CODE(00305H);(*                    btst.l d1,d5*)
  954. (*    91 00b6:*)  CODE(06706H);(*                    beq c33*)
  955. (*    92 00b8:*)  CODE(032c1H);(*                    move.w d1,(a1)+*)
  956. (*    93 00ba:*)  CODE(032c0H);(*                    move.w d0,(a1)+*)
  957. (*    94 00bc:*)  CODE(00386H);(*                    bclr.l d1,d6*)
  958. (*    95 00be:*)  CODE(05241H);(*              c33:  addq.w #1,d1*)
  959. (*    96 00c0:*)  CODE(0b242H);(*                    cmp.w d2,d1*)
  960. (*    97 00c2:*)  CODE(0640aH);(*                    bcc c3e*)
  961. (*    98 00c4:*)  CODE(00305H);(*                    btst.l d1,d5*)
  962. (*    99 00c6:*)  CODE(06706H);(*                    beq c3e*)
  963. (*   100 00c8:*)  CODE(032c1H);(*                    move.w d1,(a1)+*)
  964. (*   101 00ca:*)  CODE(032c0H);(*                    move.w d0,(a1)+*)
  965. (*   102 00cc:*)  CODE(00386H);(*                    bclr.l d1,d6*)
  966. (*   103 00ce:*)  CODE(02146H,00004H);(*       c3e:  move.l d6,4(a0)*)
  967. (*   104 00d2:*)  CODE(02489H);(*              fin:  move.l a1,(a2)*)
  968. *Stack-*)
  969. END LookAround;
  970. (*$LONG_ADDR=*)
  971. (***LookAsm-*)
  972.  
  973. (***LookM2+
  974. PROCEDURE LookAround(xi,yi : INTEGER);
  975. BEGIN
  976.   PushStack(xi - 1,yi - 1);
  977.   PushStack(xi + 1,yi - 1);
  978.   PushStack(xi + 1,yi + 1);
  979.   PushStack(xi - 1,yi + 1);
  980.  
  981.   PushStack(xi - 1,yi);
  982.   PushStack(xi,yi - 1);
  983.   PushStack(xi + 1,yi);
  984.   PushStack(xi,yi + 1);
  985.  
  986.  
  987. END LookAround;
  988. *LookM2-*)
  989.  
  990. PROCEDURE PopStack(VAR x,y : INTEGER) : BOOLEAN;
  991. BEGIN
  992. (*Queue+*)
  993.   IF StackIn = StackOut THEN
  994.     RETURN FALSE
  995.   END;
  996.   WITH StackBuffer^[StackOut] DO
  997.     x := xv;
  998.     y := yv;
  999.   END;
  1000.   StackOut := (StackOut + 1) MOD MaxStackDepth;
  1001. (*Queue-*)
  1002.  
  1003. (*Stack+
  1004.   IF Stack = StackBuffer THEN
  1005.     RETURN FALSE
  1006.   END;
  1007.   DEC(Stack,4);
  1008.   WITH Stack^ DO
  1009.     x := xv;
  1010.     y := yv;
  1011.   END;
  1012. *Stack-*)
  1013.  
  1014. (*StackCheck+
  1015.   DEC(StackDepth);
  1016. *StackCheck-*)
  1017.  
  1018.   RETURN TRUE
  1019. END PopStack;
  1020.  
  1021. PROCEDURE EmptyStack();
  1022. BEGIN
  1023. (*Queue+*)
  1024.   StackIn := 0;
  1025.   StackOut := 0;
  1026. (*Queue-*)
  1027. (*Stack+
  1028.   Stack := StackBuffer;
  1029. *Stack-*)
  1030.  
  1031. (*StackCheck+
  1032.     TermOut.WriteString("MAX Stack Depth = ");
  1033.     TermOut.WriteCard(StackDepthReached,1);
  1034.     TermOut.WriteLn;
  1035.     StackDepthReached := 0;
  1036.   StackDepth := 0;
  1037. *StackCheck-*)
  1038. END EmptyStack;
  1039.  
  1040.  
  1041. PROCEDURE Transform(VAR x,y : INTEGER) : BOOLEAN;
  1042. BEGIN
  1043.     DEC(x, LeftFieldBorder);
  1044.     IF x < 0 THEN RETURN FALSE END;
  1045.     DEC(y,TopFieldBorder);
  1046.     IF y < 0 THEN RETURN FALSE END;
  1047.     x := x DIV SquareWidth;
  1048.     y := y DIV SquareHeight;
  1049.    IF (x >= FieldWidth) OR (y >= FieldHeight) THEN
  1050.      RETURN FALSE
  1051.    END;
  1052.     RETURN TRUE
  1053. END Transform;
  1054.  
  1055. PROCEDURE InitEntryGad() : BOOLEAN;
  1056. VAR
  1057.     lp : POINTER TO LONGCARD;
  1058.     h : CARDINAL;
  1059.     strWidth : CARDINAL;
  1060.  
  1061.   PROCEDURE addpoint(x,y : INTEGER);
  1062.   BEGIN
  1063.     lp^ := LONG(x,y);
  1064.     INC(lp,4);
  1065.   END addpoint;
  1066.   
  1067. BEGIN
  1068.   IF EntryGad = NIL THEN
  1069.     strWidth :=  30 * SquareFont^.tfXSize;
  1070.     Storage.ALLOCATE(EntryGad,SIZE(EntryGad^));
  1071.     IF EntryGad = NIL THEN RETURN FALSE END;
  1072.     h := SquareFont^.tfYSize;
  1073.     WITH EntryGad^ DO
  1074.       lp := ADR(slines[0]);
  1075.       addpoint(0,0);
  1076.       addpoint(strWidth + 2,0);
  1077.       addpoint(strWidth + 2,h + 2);
  1078.       addpoint(0,h + 2);
  1079.       addpoint(0,0);
  1080.       addpoint(0,0);
  1081.       addpoint(strWidth + 2,0);
  1082.       addpoint(strWidth + 2,h + 2);
  1083.       addpoint(0,h + 2);
  1084.       addpoint(0,0);
  1085.       WITH borders[0] DO
  1086.         LeftEdge := -1;
  1087.         TopEdge := -1;
  1088.         FrontPen := BYTE(Pen1);
  1089.         DrawMode := Rasters.Jam1;
  1090.         Count := BYTE(5);
  1091.         XY := ADR(slines[0]);
  1092.         NextBorder := ADR(borders[1]);
  1093.       END;
  1094.       WITH borders[1] DO
  1095.         LeftEdge := -2;
  1096.         TopEdge := -2;
  1097.         FrontPen := BYTE(Pen2);
  1098.         DrawMode := Rasters.Jam1;
  1099.         Count := BYTE(5);
  1100.         XY := ADR(slines[5]);
  1101.       END;
  1102.       WITH se DO
  1103.         Font := SquareFont;
  1104.         Pens[0] := BYTE(1);
  1105.         Pens[1] := BYTE(0);
  1106.         ActivePens[0] := BYTE(2);
  1107.         ActivePens[1] := BYTE(3);
  1108.       END;
  1109.       WITH SI DO
  1110.         Buffer := ADR(fsBuffer);
  1111.         UndoBuffer := ADR(fsUndoBuffer);
  1112.         MaxChars := MaxStringLength + 1;
  1113.         Extension := ADR(se);
  1114.       END;
  1115.       WITH Gad DO
  1116.         TopEdge := - INTEGER(4 * h);
  1117.         LeftEdge := 5 * SquareFont^.tfXSize;
  1118.         Width := strWidth;
  1119.         Height := h;
  1120.         Flags := Intuition.GadgetFlagSet{Intuition.GRelBottom, Intuition.GFStringExtend};
  1121.         Activation := Intuition.ActivationFlagSet{Intuition.RelVerify, Intuition.StringCenter};
  1122.         GadgetType := Intuition.StrGadget;
  1123.         GadgetRenderB := ADR(borders[0]);
  1124.         GadgetText := NIL;
  1125.         SpecialInfoS := ADR(SI);
  1126.         GadgetID := strID;
  1127.       END;
  1128.     END;
  1129.   END;
  1130.   RETURN TRUE
  1131. END InitEntryGad;
  1132.  
  1133.  
  1134.  
  1135. PROCEDURE InitFields() : BOOLEAN;
  1136. VAR
  1137.     sec,mic : LONGCARD;
  1138.     i,j : INTEGER;
  1139.     x,y : CARDINAL;
  1140. BEGIN
  1141.   NumMines := MinesThisLevel;
  1142.   i := (FieldWidth * FieldHeight);
  1143.   IF NumMines > (i - 2) THEN
  1144.     NumMines := i - 2; (* Silly Person *)
  1145.   END;
  1146.   NonMinesCovered := i - NumMines;
  1147.   Restarting := TRUE;
  1148.   WaitingForNew := FALSE;
  1149.   Intuition.CurrentTime(sec,mic);
  1150.   sec := LONGCARD(LONGBITSET(sec)/LONGBITSET(mic));
  1151.   FastRandom.seed := sec;
  1152.   CoveredRow := LONGBITSET{0..FieldWidth - 1};
  1153.   FOR i := 0 TO FieldHeight - 1 DO
  1154.     WITH FieldRows[i] DO
  1155.       Mines := LONGBITSET{};
  1156.       Covered := CoveredRow;
  1157.       Guessed := LONGBITSET{};
  1158.       Wondered := LONGBITSET{};
  1159.     END
  1160.   END;
  1161.   i := 0;
  1162.   WHILE i < NumMines DO
  1163.     x := FastRandom.Random(FieldWidth);
  1164.     y := FastRandom.Random(FieldHeight);
  1165.     WITH FieldRows[y] DO
  1166.       IF ~(x IN Mines) THEN
  1167.         INCL(Mines,x);
  1168.         INC(i);
  1169.       END;
  1170.     END;
  1171.   END;
  1172.   GuessedMines := 0;
  1173.   GuessedRightMines := 0;
  1174.   RETURN TRUE
  1175. END InitFields;
  1176.  
  1177. PROCEDURE ShowSquare(x,y : CARDINAL; state : SquareState);
  1178. VAR
  1179.     square : Intuition.ImagePtr;
  1180. BEGIN
  1181.   x := SquareWidth * x + CARDINAL(LeftFieldBorder);
  1182.   y := CARDINAL(SquareHeight) * y + CARDINAL(TopFieldBorder);
  1183.   Intuition.DrawImage(FieldRPort,SquareImages[ORD(state)],x,y)
  1184. END ShowSquare;
  1185.  
  1186.  
  1187. PROCEDURE MySizeWindow(tw,th : INTEGER) : BOOLEAN;
  1188. VAR
  1189.     msg : Intuition.IntuiMessagePtr;
  1190.     port : Ports.MsgPortPtr;
  1191.     dx,dy : INTEGER;
  1192. BEGIN
  1193.   WITH FieldWindow^ DO
  1194.     IF tw > WScreen^.Width THEN
  1195.       RETURN FALSE
  1196.     END;
  1197.     IF th > WScreen^.Height THEN
  1198.       RETURN FALSE
  1199.     END;
  1200.     port := UserPort;
  1201.     dx := tw - Width;
  1202.     dy := th - Height;
  1203.     IF LeftEdge + tw > WScreen^.Width THEN
  1204.       Intuition.MoveWindow(FieldWindow,WScreen^.Width - tw - LeftEdge,0);
  1205.     END;
  1206.     IF TopEdge + th > WScreen^.Height THEN
  1207.       Intuition.MoveWindow(FieldWindow,0,WScreen^.Height - th - TopEdge);
  1208.     END;
  1209.   END;
  1210.   Intuition.SizeWindow(FieldWindow,dx,dy);
  1211.   WindowSized := TRUE;
  1212. (*
  1213.   LOOP
  1214.     LOOP
  1215.       msg := Ports.GetMsg(port);
  1216.       IF msg # NIL THEN EXIT END;
  1217.       msg := Ports.WaitPort(port);
  1218.     END;
  1219.     IF Intuition.RefreshWindow IN msg^.Class THEN
  1220.       Intuition.BeginRefresh(FieldWindow);
  1221.       Intuition.EndRefresh(FieldWindow, TRUE);
  1222.     END;
  1223.     IF Intuition.NewSize IN msg^.Class THEN
  1224.       EXIT
  1225.     END;
  1226.     Ports.ReplyMsg(msg);
  1227.   END;
  1228.   Ports.ReplyMsg(msg);
  1229. *)
  1230.   RETURN TRUE;
  1231. END MySizeWindow;
  1232.  
  1233. PROCEDURE MenuCheckedIf(b:BOOLEAN);
  1234. BEGIN
  1235.   IF b THEN
  1236.     INCL(EasyMenus.nextItemFlags,Intuition.Checked)
  1237.   ELSE
  1238.     EXCL(EasyMenus.nextItemFlags,Intuition.Checked)
  1239.   END
  1240. END MenuCheckedIf;
  1241.  
  1242. PROCEDURE OpenFonts();
  1243. VAR
  1244.     vp : Views.ViewPtr;
  1245. BEGIN
  1246. (*
  1247.   CountFontAttrPtr := ADR(CountFontAttr);
  1248. *)
  1249.   WITH SquareFontAttr DO
  1250.     taName  := ADR(SquareFontName);
  1251.     taYSize := SquareFontSize;
  1252.     taStyle := Text.NormalStyle;
  1253.     taFlags := Text.FontFlagSet{Text.DiskFont};
  1254.     vp := Intuition.ViewAddress();
  1255.     IF Views.HiRes IN vp^.Modes THEN
  1256.       IF ~(Views.Lace IN vp^.Modes) THEN
  1257.         INCL(taFlags,Text.TallDot)
  1258.       END
  1259.     ELSE
  1260.       IF Views.Lace IN vp^.Modes THEN
  1261.         INCL(taFlags,Text.LongDot)
  1262.       END
  1263.     END
  1264.   END;
  1265.  
  1266.   SquareFontAttrPtr := NIL;
  1267.   IF Laced THEN
  1268.     SquareFontAttrPtr := ADR(SquareFontAttr);
  1269.   END;
  1270.  
  1271.   SquareFont := EasyText.EasyOpenFont(SquareFontAttrPtr);
  1272.   IF SquareFont = NIL THEN
  1273.     SquareFontAttrPtr := NIL;
  1274.     SquareFont := EasyText.EasyOpenFont(SquareFontAttrPtr)
  1275.   END;
  1276.   WITH SquareFont^ DO
  1277.     LeftSquareText := LeftFieldBorder + (SquareWidth - INTEGER(tfXSize)) DIV 2;
  1278.     TopSquareText := TopFieldBorder + (SquareHeight - INTEGER(tfYSize)) DIV 2;
  1279.   END;
  1280. END OpenFonts;
  1281.  
  1282. PROCEDURE CreateMenus();
  1283. BEGIN
  1284.   menu := NIL;
  1285. (*  IF V36 THEN*)
  1286.     EasyMenus.nextTextAttr := ADR(SquareFontAttr);
  1287.     EasyMenus.nextItemHeight := SquareFont^.tfYSize + 2;
  1288. (*  END;*)
  1289.  
  1290.       
  1291.   EasyMenus.StartStrip;
  1292.  
  1293.   EasyMenus.nextFrontPen := 2;
  1294.   EasyMenus.nextBackPen := 1;
  1295.   EasyMenus.nextIntuiTopEdge := 0;
  1296.  
  1297.   EasyMenus.AddMenu(GameText, Intuition.CheckWidth + (Intuition.CommWidth * 2) + SquareFont^.tfXSize * 12);
  1298.  
  1299.   EasyMenus.AddItem("New",'N');
  1300.  
  1301.   INCL(EasyMenus.nextItemFlags,Intuition.CheckIt);
  1302.  
  1303.   MenuCheckedIf(Level = Beginner);
  1304.   EasyMenus.AddItem(BeginnerString,'B');
  1305.   EasyMenus.currentItem^.MutualExclude := LONGBITSET{2,3,4};
  1306.  
  1307.   MenuCheckedIf(Level = Intermediate);
  1308.   EasyMenus.AddItem(IntermediateString,'I');
  1309.   EasyMenus.currentItem^.MutualExclude := LONGBITSET{1,3,4};
  1310.  
  1311.   MenuCheckedIf(Level = Expert);
  1312.   EasyMenus.AddItem(ExpertString,'E');
  1313.   EasyMenus.currentItem^.MutualExclude := LONGBITSET{1,2,4};
  1314.  
  1315.   MenuCheckedIf(Level = Custom);
  1316.   EasyMenus.AddItem(CustomString,'C');
  1317.   EasyMenus.currentItem^.MutualExclude := LONGBITSET{1,2,3};
  1318.  
  1319.   INCL(EasyMenus.nextItemFlags,Intuition.MenuToggle);
  1320.  
  1321.   MenuCheckedIf(Questions);
  1322.   EasyMenus.AddItem("Marks (?)",'M');
  1323.   
  1324.   EasyMenus.nextItemFlags := Intuition.ItemFlagSet{Intuition.ItemText, Intuition.ItemEnabled} + Intuition.HighComp;
  1325.   EasyMenus.AddItem("Cursor",0C);
  1326.   EasyMenus.nextSubLeftEdge := EasyMenus.nextItemLeftEdge + EasyMenus.nextItemWidth - 20;
  1327.   EasyMenus.nextSubHeight := EasyMenus.nextItemHeight;
  1328.   EasyMenus.nextSubWidth := SquareFont^.tfXSize * 9;
  1329.   EasyMenus.nextSubFlags := Intuition.ItemFlagSet{Intuition.ItemText, Intuition.ItemEnabled, Intuition.CheckIt} + Intuition.HighComp;
  1330.   IF MovingAllowed THEN
  1331.     INCL(EasyMenus.nextSubFlags,Intuition.Checked)
  1332.   ELSE
  1333.     EXCL(EasyMenus.nextSubFlags,Intuition.Checked)
  1334.   END;
  1335.   EasyMenus.AddSub("Mobile",0C);
  1336.   EasyMenus.currentSub^.MutualExclude := LONGBITSET{1};
  1337.   IF MovingAllowed THEN
  1338.     EXCL(EasyMenus.nextSubFlags,Intuition.Checked)
  1339.   ELSE
  1340.     INCL(EasyMenus.nextSubFlags,Intuition.Checked)
  1341.   END;
  1342.   EasyMenus.AddSub("Static",0C);
  1343.   EasyMenus.currentSub^.MutualExclude := LONGBITSET{0};
  1344.  
  1345.   EasyMenus.nextItemFlags := Intuition.ItemFlagSet{Intuition.ItemText, Intuition.ItemEnabled, Intuition.MenuToggle, Intuition.CheckIt} + Intuition.HighComp;
  1346.   MenuCheckedIf(SafeIfMarked);
  1347.   EasyMenus.AddItem("Safe If Marked",0C);
  1348.  
  1349.   EasyMenus.nextItemFlags := Intuition.ItemFlagSet{Intuition.ItemText, Intuition.ItemEnabled} + Intuition.HighComp;
  1350.   EasyMenus.AddItem("Best Times",'T');
  1351.   EasyMenus.AddItem("About MineSweeper",'?');
  1352.   EasyMenus.AddItem("Pause",'P');
  1353.   EasyMenus.AddItem("Quit",'Q');
  1354.  
  1355. (*  EasyMenus.AddItem("Test",0C);*)
  1356.  
  1357.   EasyMenus.AddMenu(CompleteText,Intuition.CheckWidth + (Intuition.CommWidth * 2) + SquareFont^.tfXSize * 12);
  1358.   
  1359.   EasyMenus.nextItemFlags := Intuition.ItemFlagSet{Intuition.ItemText, Intuition.ItemEnabled, Intuition.CheckIt} + Intuition.HighComp;
  1360.   MenuCheckedIf(CompleteMethod = AllMinesFound);
  1361.   EasyMenus.AddItem("All Mines Found",0C);
  1362.   EasyMenus.currentItem^.MutualExclude := LONGBITSET{1,2,3};
  1363.   MenuCheckedIf(CompleteMethod = AllNonMinesFound);
  1364.   EasyMenus.AddItem("All Non Mines Found",0C);
  1365.   EasyMenus.currentItem^.MutualExclude := LONGBITSET{0,2,3};
  1366.   MenuCheckedIf(CompleteMethod = AllSquaresFound);
  1367.   EasyMenus.AddItem("Both",0C);
  1368.   EasyMenus.currentItem^.MutualExclude := LONGBITSET{0,1,3};
  1369.   MenuCheckedIf(CompleteMethod = EitherCompletion);
  1370.   EasyMenus.AddItem("Either",0C);
  1371.   EasyMenus.currentItem^.MutualExclude := LONGBITSET{0,1,2};
  1372.   
  1373.   IF ~EasyMenus.stripFailed THEN
  1374.     menu := EasyMenus.currentStrip;
  1375.   END;
  1376. END CreateMenus;
  1377.  
  1378. PROCEDURE CreateFieldWindow() : BOOLEAN;
  1379. VAR
  1380.     nw : Intuition.NewWindowPtr;
  1381.     FullWindowWidth, FullWindowHeight, gadpos, TextOffset : INTEGER;
  1382.     TooBig, Sized : BOOLEAN;
  1383. BEGIN
  1384.   Sized := FALSE;
  1385.   FieldWindowWidth := SquareWidth * FieldWidth;
  1386.   FieldWindowHeight := SquareHeight * FieldHeight;
  1387.   RightFieldBorder := LeftFieldBorder + FieldWindowWidth - 1;
  1388.   FullWindowWidth := FieldWindowWidth + LeftFieldBorder + RightWindowBorder;
  1389.   FullWindowHeight := FieldWindowHeight + TopFieldBorder + BottomWindowBorder;
  1390.   IF FieldWindow = NIL THEN
  1391.     Storage.ALLOCATE(nw,SIZE(nw^));
  1392.     IF nw = NIL THEN RETURN FALSE END;
  1393.     WITH nw^ DO
  1394.       LeftEdge := HighScores^.InitX;
  1395.       TopEdge := HighScores^.InitY;
  1396.       Width := FullWindowWidth;
  1397.       Height := FullWindowHeight;
  1398.       DetailPen := BYTE(2);
  1399.       BlockPen := BYTE(1);
  1400.       IDCMPFlags := NormalIDCMPs;
  1401.       Flags :=
  1402.        Intuition.WindowFlagSet{Intuition.WindowDrag,Intuition.WindowDepth,
  1403.                                Intuition.WindowClose,Intuition.Activate,
  1404.                                Intuition.ReportMouseFlag
  1405.                               } + Intuition.SimpleRefresh;
  1406.       CheckMark := SquareImages[GuessImage];
  1407.       Title := ADR(MineSweeperName);
  1408.       Type := Intuition.WBenchScreen;
  1409.     END;
  1410.     Storage.ALLOCATE(NewGameGad,SIZE(NewGameGad^) (* * 2*) );
  1411.     IF NewGameGad = NIL THEN
  1412.       RETURN FALSE
  1413.     END;
  1414.     FieldWindow := Intuition.OpenWindow(nw);
  1415.     IF FieldWindow = NIL THEN
  1416.       nw^.LeftEdge := 0;
  1417.       nw^.TopEdge := 0;
  1418.       FieldWindow := Intuition.OpenWindow(nw);
  1419.       IF FieldWindow = NIL THEN
  1420.         IF Level # Beginner THEN
  1421.           Storage.DEALLOCATE(nw,0);
  1422.           Storage.DEALLOCATE(NewGameGad,0);
  1423.           SetSize(Beginner);
  1424.           RETURN CreateFieldWindow()
  1425.         END;
  1426.       END
  1427.     END;
  1428.     IF menu # NIL THEN
  1429.       menu^.Width := Text.TextLength(ADR(FieldWindow^.WScreen^.RPort),ADR(GameText),GameTextLen) * 2;
  1430.       WITH menu^.NextMenu^ DO
  1431.         Width := Text.TextLength(ADR(FieldWindow^.WScreen^.RPort),ADR(CompleteText),CompleteTextLen) * 2;
  1432.         LeftEdge := menu^.LeftEdge + menu^.Width + 10;
  1433.       END;
  1434.       Intuition.SetMenuStrip(FieldWindow,menu)
  1435.     END;
  1436.     Pointer.SetMyPointer(FieldWindow);
  1437.     Storage.DEALLOCATE(nw,0);
  1438.     FieldRPort := FieldWindow^.RPort;
  1439.     Pens.SetWrMsk(FieldRPort,{0,1});
  1440. (*
  1441.     WITH FieldRPort^ DO
  1442.       TermOut.WriteString("Mask = ");
  1443.       TermOut.WriteHex(CARDINAL(Mask),1);
  1444.       TermOut.WriteString("\nAreaPtrn = ");
  1445.       TermOut.WriteLongHex(AreaPtrn,1);
  1446.       TermOut.WriteString("\nAreaPtSz = ");
  1447.       TermOut.WriteInt(INTEGER(AreaPtSz),1);
  1448.       TermOut.WriteLn;
  1449.     END;
  1450. *)
  1451.     FindColourScheme;
  1452.  
  1453.  
  1454.     
  1455.     WITH FieldWindow^ DO
  1456.       MainProcess^.prWindowPtr := FieldWindow;
  1457.       WindowBit := Tasks.SIGNAL(UserPort^.mpSigBit);
  1458.       IF ~InitClip(CARDINAL(WScreen^.BMap.Depth)) THEN
  1459.         RETURN FALSE
  1460.       END;
  1461.       (*Intuition.RefreshWindowFrame(FieldWindow);*)
  1462.       Pens.SetDrMd(RPort,Rasters.Jam1);
  1463.     END;
  1464.     WITH NewGameGad^ DO
  1465.       NextGadget := NIL;
  1466.       GadgetRenderI := dataPtr^.Images[SmileyImage];
  1467.       SelectRenderI := dataPtr^.Images[AstonishedImage];
  1468.       Width := GadgetRenderI^.Width;
  1469.       Height := GadgetRenderI^.Height;
  1470.       LeftEdge := (FieldWindowWidth DIV 2) + LeftFieldBorder - (Width DIV 2);
  1471.       TopEdge := TopWindowBorder + (TopWindowArea - Height) DIV 2;
  1472.       Flags := Intuition.GadgetFlagSet{Intuition.GadgImage} + Intuition.GadgHImage;
  1473.       Activation := Intuition.ActivationFlagSet{Intuition.RelVerify};
  1474.       GadgetType := Intuition.BoolGadget;
  1475.       GadgetID := NewGameID;
  1476.     END;
  1477.     gadpos := Intuition.AddGList(FieldWindow,NewGameGad,-1,2,NIL);
  1478.       IF ~MySizeWindow(FullWindowWidth, FullWindowHeight) THEN
  1479.         IF Level # Beginner THEN
  1480.           SetSize(Beginner);
  1481.           RETURN CreateFieldWindow()
  1482.         END;
  1483.         Intuition.CloseWindow(FieldWindow);
  1484.         RETURN FALSE
  1485.       END;
  1486.       Sized := TRUE;
  1487.   ELSE
  1488.     gadpos := Intuition.RemoveGadget(FieldWindow,NewGameGad);
  1489.     IF (LastFieldWidth # FieldWidth) OR (LastFieldHeight # FieldHeight) THEN
  1490.       IF ~MySizeWindow(FullWindowWidth, FullWindowHeight) THEN
  1491.         IF Level = Beginner THEN
  1492.           RETURN FALSE
  1493.         END;
  1494.         DEC(Level);
  1495.         SetSize(Level);
  1496.         RETURN CreateFieldWindow()
  1497.       END;
  1498.     END;
  1499.     WITH NewGameGad^ DO
  1500.       GadgetRenderI := dataPtr^.Images[SmileyImage];
  1501.       SelectRenderI := dataPtr^.Images[AstonishedImage];
  1502.       LeftEdge := (FieldWindowWidth DIV 2) + LeftFieldBorder - (Width DIV 2);
  1503.       TopEdge := TopWindowBorder + (TopWindowArea - Height) DIV 2;
  1504.     END;
  1505.     gadpos := Intuition.AddGadget(FieldWindow,NewGameGad,-1);
  1506.   END;
  1507.   LastFieldWidth := FieldWidth;
  1508.   LastFieldHeight := FieldHeight;
  1509.   TooBig := FALSE;
  1510.   TopTextBorder := TopWindowBorder + (TopWindowArea - 14 (*INTEGER(CountFont^.tfYSize)*)) DIV 2;
  1511.   TextWidth := (4 * 10 (*CountFont^.tfXSize*)) + 1;
  1512.   TextHeight := 14 (*CountFont^.tfYSize*) + 1;
  1513.   TextOffset := (NewGameGad^.LeftEdge - LeftFieldBorder - TextWidth) DIV 2;
  1514.   LeftTextBorder := LeftFieldBorder + TextOffset;
  1515.   RightTextBorder := NewGameGad^.LeftEdge + NewGameGad^.Width + TextOffset - 1;
  1516.   IF ODD(LeftTextBorder) THEN DEC(LeftTextBorder) END;
  1517.   IF ODD(RightTextBorder) THEN DEC(RightTextBorder) END;
  1518.   WITH NewGameGad^ DO
  1519.     SmileX := LeftEdge;
  1520.     SmileY := TopEdge;
  1521.   END;
  1522.   IF Shrunk THEN
  1523.     Shrunk := FALSE;
  1524.     (*RefreshDisplay(TRUE);*)
  1525.     IF ~WaitingForNew THEN StartTimer END;
  1526.     RETURN TRUE
  1527.   END;
  1528.   IF InitFields() THEN
  1529.     Intuition.ModifyIDCMP(FieldWindow,NormalIDCMPs);
  1530.     INCL(FieldWindow^.Flags,Intuition.ReportMouseFlag);
  1531.     RETURN TRUE
  1532.   ELSE
  1533.     RETURN FALSE
  1534.   END
  1535. END CreateFieldWindow;
  1536.  
  1537.  
  1538.  
  1539. (*
  1540. PROCEDURE Count(Field : FieldType; xi,yi : INTEGER) : CARDINAL;
  1541.  
  1542.   PROCEDURE TestSquare(xi,yi : INTEGER) : CARDINAL;
  1543.   VAR b : BOOLEAN;
  1544.   BEGIN
  1545.     IF (CARDINAL(xi) < CARDINAL(FieldWidth)) & (CARDINAL(yi) < CARDINAL(FieldHeight)) THEN
  1546.       WITH FieldRows[CARDINAL(yi)] DO
  1547.         CASE Field OF
  1548.         | fMines    : b := CARDINAL(xi) IN Mines;
  1549.         | fCovered  : b := CARDINAL(xi) IN Covered;
  1550.         | fGuessed  : b := CARDINAL(xi) IN Guessed;
  1551.         | fWondered : b := CARDINAL(xi) IN Wondered;
  1552.         END;
  1553.       END;
  1554.       RETURN CARDINAL(b);
  1555.     END;
  1556.     RETURN 0
  1557.   END TestSquare;
  1558.  
  1559. BEGIN
  1560.   RETURN
  1561.     TestSquare(xi-1,yi-1)
  1562.  +  TestSquare(xi,yi-1)
  1563.  +  TestSquare(xi+1,yi-1)
  1564.  +  TestSquare(xi-1,yi)
  1565.  +  TestSquare(xi+1,yi)
  1566.  +  TestSquare(xi-1,yi+1)
  1567.  +  TestSquare(xi,yi+1)
  1568.  +  TestSquare(xi+1,yi+1);
  1569. END Count;
  1570. *)
  1571.  
  1572. PROCEDURE Count(Field : FieldType; xi,yi : INTEGER) : CARDINAL;
  1573. BEGIN
  1574.     SETREG(8,ADR(FieldRows));
  1575.     SETREG(1,FieldWidth);
  1576.     SETREG(2,FieldHeight);
  1577.     SETREG(3,xi);
  1578.     SETREG(4,yi);
  1579.     SETREG(5,Field);
  1580. (*     2 0000:                    ;        a0 = address of FieldRows*)
  1581. (*     3 0000:                    ;        d0 = result*)
  1582. (*     4 0000:                    ;        d1 = FieldWidth*)
  1583. (*     5 0000:                    ;        d2 = FieldHeight*)
  1584. (*     6 0000:                    ;        d3 = x*)
  1585. (*     7 0000:                    ;        d4 = y*)
  1586. (*     8 0000:                    ;        d5 = offset of field in row, eg 0 = mines, 1 = Covered etc*)
  1587. (*     9 0000:*)  CODE(05343H);(*                      subq.w #1,d3*)
  1588. (*    10 0002:*)  CODE(05344H);(*                      subq.w #1,d4*)
  1589. (*    11 0004:*)  CODE(07000H);(*                      moveq.l #0,d0*)
  1590. (*    12 0006:*)  CODE(0611eH);(*                      bsr one    ; x-1,y-1*)
  1591. (*    13 0008:*)  CODE(05243H);(*                      addq.w #1,d3*)
  1592. (*    14 000a:*)  CODE(0611aH);(*                      bsr one    ;   x,y-1*)
  1593. (*    15 000c:*)  CODE(05243H);(*                      addq.w #1,d3*)
  1594. (*    16 000e:*)  CODE(06116H);(*                      bsr one    ; x+1,y-1*)
  1595. (*    17 0010:*)  CODE(05244H);(*                      addq.w #1,d4*)
  1596. (*    18 0012:*)  CODE(06112H);(*                      bsr one    ; x+1,y*)
  1597. (*    19 0014:*)  CODE(05543H);(*                      subq.w #2,d3*)
  1598. (*    20 0016:                            ;bsr one    ;   x,y - don't test square itself*)
  1599. (*    21 0016:                            ;subq.w #1,d3*)
  1600. (*    22 0016:*)  CODE(0610eH);(*                      bsr one    ; x-1,y*)
  1601. (*    23 0018:*)  CODE(05244H);(*                      addq.w #1,d4*)
  1602. (*    24 001a:*)  CODE(0610aH);(*                      bsr one    ; x-1,y+1*)
  1603. (*    25 001c:*)  CODE(05243H);(*                      addq.w #1,d3*)
  1604. (*    26 001e:*)  CODE(06106H);(*                      bsr one    ;   x,y+1*)
  1605. (*    27 0020:*)  CODE(05243H);(*                      addq.w #1,d3*)
  1606. (*    28 0022:*)  CODE(06102H);(*                      bsr one    ; x+1,y+1*)
  1607. (*    29 0024:*)  CODE(0601cH);(*                      bra.s fin*)
  1608. (*    30 0026:                    *)
  1609. (*    31 0026:*)  CODE(0b641H);(*              one:    cmp.w d1,d3*)
  1610. (*    32 0028:*)  CODE(06416H);(*                      bcc.s out*)
  1611. (*    33 002a:*)  CODE(0b842H);(*                      cmp.w d2,d4*)
  1612. (*    34 002c:*)  CODE(06412H);(*                      bcc.s out*)
  1613. (*    35 002e:*)  CODE(03c04H);(*                      move.w d4,d6*)
  1614. (*    36 0030:*)  CODE(0e546H);(*                      asl.w #2,d6*)
  1615. (*    37 0032:*)  CODE(0dc45H);(*                      add.w d5,d6*)
  1616. (*    38 0034:*)  CODE(0e546H);(*                      asl.w #2,d6*)
  1617. (*    39 0036:*)  CODE(02c30H,06000H);(*              move.l (0,a0,d6),d6*)
  1618. (*    40 003a:*)  CODE(00706H);(*                      btst.l d3,d6*)
  1619. (*    41 003c:*)  CODE(06702H);(*                      beq.s out*)
  1620. (*    42 003e:*)  CODE(05280H);(*                      addq.l #1,d0*)
  1621. (*    43 0040:*)  CODE(04e75H);(*              out:    rts*)
  1622. (*    44 0042:  4e71              fin:    nop*)
  1623. END Count;
  1624.  
  1625. (*
  1626. PROCEDURE StateOfSquare(x,y : CARDINAL) : SquareState;
  1627. VAR
  1628.     state : SquareState;
  1629. BEGIN
  1630.   WITH FieldRows[y] DO
  1631.     IF x IN Covered THEN
  1632.       state := UnknownState
  1633.       IF x IN Wondered THEN
  1634.         state := WonderState
  1635.         IF x IN Guessed THEN
  1636.           state := GuessState
  1637.         END
  1638.       END
  1639.     ELSE
  1640.       state := BlankState;
  1641.       IF x IN Mines THEN
  1642.         state := MineState
  1643.       END
  1644.     END;
  1645.   END;
  1646.   RETURN state;
  1647. END StateOfSquare;
  1648. *)
  1649.  
  1650. (*$X-*)
  1651. PROCEDURE ChunkyTable();
  1652. BEGIN
  1653.   CODE(0101H,0101H,0000H,0203H,0404H,0404H,0000H,0203H);
  1654.   CODE(0101H,0106H,0000H,0206H,0505H,0505H,0404H,0403H);
  1655. END ChunkyTable;
  1656.  
  1657.  
  1658. PROCEDURE StateOfSquare(x,y : CARDINAL) : SquareState;
  1659. (* This routine uses the Chunky table to convert from an
  1660.    element in a 2D bitmap to a SquareState
  1661. *)
  1662. BEGIN
  1663.     SETREG(1,y);
  1664.     SETREG(3,x);
  1665.     SETREG(8,ADR(FieldRows));
  1666.     SETREG(9,CT);
  1667.     SETREG(0,WaitingForNew);
  1668. (*     2 0000:*)  CODE(0e949H);(*                      lsl.w #4,d1*)
  1669. (*     3 0002:*)  CODE(0e908H);(*                      lsl.b #4,d0*)
  1670. (*     4 0004:*)  CODE(0d0c1H);(*                      adda.w d1,a0*)
  1671. (*     5 0006:*)  CODE(02418H);(*                      move.l (a0)+,d2*)
  1672. (*     6 0008:*)  CODE(00702H);(*                      btst.l d3,d2*)
  1673. (*     7 000a:*)  CODE(06704H);(*                      beq.s b0*)
  1674. (*     8 000c:*)  CODE(008c0H,00003H);(*               bset.l #3,d0*)
  1675. (*     9 0010:*)  CODE(02418H);(*              b0:    move.l (a0)+,d2*)
  1676. (*    10 0012:*)  CODE(00702H);(*                      btst.l d3,d2*)
  1677. (*    11 0014:*)  CODE(06704H);(*                      beq.s b1*)
  1678. (*    12 0016:*)  CODE(008c0H,00002H);(*               bset.l #2,d0*)
  1679. (*    13 001a:*)  CODE(02418H);(*              b1:    move.l (a0)+,d2*)
  1680. (*    14 001c:*)  CODE(00702H);(*                      btst.l d3,d2*)
  1681. (*    15 001e:*)  CODE(06704H);(*                      beq.s b2*)
  1682. (*    16 0020:*)  CODE(008c0H,00000H);(*               bset.l #0,d0*)
  1683. (*    17 0024:*)  CODE(02410H);(*              b2:    move.l (a0),d2*)
  1684. (*    18 0026:*)  CODE(00702H);(*                      btst.l d3,d2*)
  1685. (*    19 0028:*)  CODE(06704H);(*                      beq.s b3*)
  1686. (*    20 002a:*)  CODE(008c0H,00001H);(*               bset.l #1,d0*)
  1687. (*    21 002e:*)  CODE(01031H,00000H);(*       b3:    move.b 0(a1,d0.w),d0*)
  1688. END StateOfSquare;
  1689.  
  1690.  
  1691. PROCEDURE ShowASquare(x,y : CARDINAL);
  1692. VAR
  1693.     square : Intuition.ImagePtr;
  1694.     state : SquareState;
  1695.     xp,yp : CARDINAL;
  1696.     b : BOOLEAN;
  1697.     str : CHAR;
  1698. BEGIN
  1699.   state := StateOfSquare(x,y);
  1700.   xp := SquareWidth * x;
  1701.   yp := CARDINAL(SquareHeight) * y;
  1702.   Intuition.DrawImage(FieldRPort,SquareImages[ORD(state)],xp  + CARDINAL(LeftFieldBorder),yp  + CARDINAL(TopFieldBorder));
  1703.   IF state = BlankState THEN
  1704.     LastSquareCount := Count(fMines,x,y);
  1705.     IF LastSquareCount > 0 THEN
  1706.       str := CHR(ORD('0') + LastSquareCount);
  1707.       EasyText.DoShadowWrite
  1708.         (    SquareFont,FieldRPort,ADR(str),
  1709.             CARDINAL(LeftSquareText) + xp,CARDINAL(TopSquareText) + yp,
  1710.             CARDINAL(ColourPens[VAL(ColourNames,LastSquareCount)]),Pen1,1
  1711.         );
  1712.     END
  1713.   END
  1714. END ShowASquare;
  1715.  
  1716.  
  1717. PROCEDURE Chunky(row : CARDINAL);
  1718. BEGIN
  1719.   SETREG(8,ADR(FieldRows));
  1720.   SETREG(0,row);
  1721.   SETREG(1,WaitingForNew);
  1722.   SETREG(9,ADR(ChunkyBuf));
  1723.   SETREG(10,CT);
  1724.   SETREG(6,FieldWidth);
  1725. (*     1 0000:*)  CODE(0e980H);(*                      asl.l #4,d0*)
  1726. (*     2 0002:*)  CODE(0d1c0H);(*                      adda.l d0,a0*)
  1727. (*     3 0004:*)  CODE(0e901H);(*                      asl.b #4,d1*)
  1728. (*     4 0006:*)  CODE(0d5c1H);(*                      adda.l d1,a2*)
  1729. (*     5 0008:*)  CODE(07000H);(*                      moveq.l #0,d0*)
  1730. (*     6 000a:*)  CODE(02418H);(*                      move.l (a0)+,d2    ;Mines*)
  1731. (*     7 000c:*)  CODE(02618H);(*                      move.l (a0)+,d3    ;Covered*)
  1732. (*     8 000e:*)  CODE(02818H);(*                      move.l (a0)+,d4    ;Guessed*)
  1733. (*     9 0010:*)  CODE(02a10H);(*                      move.l (a0),d5        ;Wondered*)
  1734. (*    10 0012:*)  CODE(05386H);(*                      subq.l #1,d6*)
  1735. (*    11 0014:*)  CODE(07e00H);(*              l0:    moveq.l #0,d7*)
  1736. (*    12 0016:*)  CODE(00102H);(*                      btst.l d0,d2*)
  1737. (*    13 0018:*)  CODE(06702H);(*                      beq.s co*)
  1738. (*    14 001a:*)  CODE(05007H);(*                      addq.b #8,d7*)
  1739. (*    15 001c:*)  CODE(00103H);(*              co:    btst.l d0,d3*)
  1740. (*    16 001e:*)  CODE(06702H);(*                      beq.s wo*)
  1741. (*    17 0020:*)  CODE(05807H);(*                      addq.b #4,d7*)
  1742. (*    18 0022:*)  CODE(00105H);(*              wo:    btst.l d0,d5*)
  1743. (*    19 0024:*)  CODE(06702H);(*                      beq.s gu*)
  1744. (*    20 0026:*)  CODE(05407H);(*                      addq.b #2,d7*)
  1745. (*    21 0028:*)  CODE(00104H);(*              gu:    btst.l d0,d4*)
  1746. (*    22 002a:*)  CODE(06702H);(*                      beq.s wb*)
  1747. (*    23 002c:*)  CODE(05207H);(*                      addq.b #1,d7*)
  1748. (*    24 002e:*)  CODE(012f2H,07800H);(*       wb:    move.b 0(a2,d7.l),(a1)+*)
  1749. (*    25 0032:*)  CODE(05200H);(*                      addq.b #1,d0*)
  1750. (*    26 0034:*)  CODE(051ceH,0ffdeH);(*               dbra d6,l0*)
  1751. END Chunky;
  1752.  
  1753. (*$X-*)
  1754. PROCEDURE TestChunkyTable();
  1755. BEGIN
  1756.   CODE(0001H,0203H,0405H,0607H,0809H,0A0BH,0C0DH,0E0FH);
  1757.   CODE(1011H,1213H,1415H,1617H,1819H,1A1BH,1C1DH,1E1FH);
  1758. END TestChunkyTable;
  1759.  
  1760.  
  1761. PROCEDURE ShowARow(y : CARDINAL);
  1762. (* Refresh one row of the display *)
  1763. VAR
  1764.     state : SquareState;
  1765.     x, xp,yp,xt,yt : CARDINAL;
  1766.     sqv : INTEGER;
  1767.     str : CHAR;
  1768.     cp : POINTER TO SquareState;
  1769. BEGIN
  1770.   x := 0;
  1771.   xp := CARDINAL(LeftFieldBorder);
  1772.   xt := CARDINAL(LeftSquareText);
  1773.   yp := (CARDINAL(SquareHeight) * y);
  1774.   yt := yp;
  1775.   INC(yp, CARDINAL(TopFieldBorder));
  1776.   INC(yt, CARDINAL(TopSquareText));
  1777.   Chunky(y);
  1778.   cp := ADR(ChunkyBuf);
  1779.   REPEAT
  1780.     state := cp^;
  1781.     INC(cp);
  1782.     Intuition.DrawImage(FieldRPort,SquareImages[ORD(state)],xp,yp);
  1783.     IF state = BlankState THEN
  1784.       sqv := Count(fMines,x,y);
  1785.       IF sqv > 0 THEN
  1786.         str := CHR(ORD('0') + sqv);
  1787.         EasyText.DoShadowWrite(SquareFont,FieldRPort,ADR(str),xt,yt,CARDINAL(ColourPens[VAL(ColourNames,sqv)]),Pen1,1);
  1788.       END
  1789.     END;
  1790.     INC(x);
  1791.     INC(xp,SquareWidth);
  1792.     INC(xt,SquareWidth);
  1793.   UNTIL x = CARDINAL(FieldWidth);
  1794. END ShowARow;
  1795.  
  1796. (*ShowStates+
  1797. PROCEDURE ShowStates();
  1798. VAR
  1799.     cp : POINTER TO SquareState;
  1800.     x,y : INTEGER;
  1801. BEGIN
  1802.   CT := ADR(TestChunkyTable);
  1803.   FOR y := 0 TO FieldHeight - 1 DO
  1804.     Chunky(y);
  1805.     cp := ADR(ChunkyBuf);
  1806.     FOR x := 0 TO FieldWidth - 1 DO
  1807.       TermOut.WriteHex(CARDINAL(cp^),2);
  1808.       INC(cp);
  1809.     END;
  1810.     TermOut.WriteLn;
  1811.  
  1812.     FOR x := 0 TO FieldWidth - 1 DO
  1813.       TermOut.WriteHex(CARDINAL(StateOfSquare(x,y)),2);
  1814.     END;
  1815.     TermOut.WriteLn;
  1816.     TermOut.WriteLn;
  1817.   END;
  1818.   CT := ADR(ChunkyTable);
  1819. END ShowStates;
  1820. *ShowStates-*)
  1821.  
  1822. (*
  1823. PROCEDURE ShowARow(y : CARDINAL);
  1824. VAR
  1825.     square : Intuition.ImagePtr;
  1826.     state : SquareState;
  1827.     x, xp,yp, xt, yt : CARDINAL;
  1828.     sqv : INTEGER;
  1829.     str : ARRAY [0..1] OF CHAR;
  1830. BEGIN
  1831.   x := 0;
  1832.   xp := 0;
  1833.   yp := CARDINAL(SquareHeight) * y;
  1834.   WITH FieldRows[y] DO
  1835.     REPEAT
  1836.       IF x IN Covered THEN
  1837.         state := UnknownState;
  1838.         IF x IN Wondered THEN
  1839.           state := WonderState;
  1840.           IF x IN Guessed THEN
  1841.             state := GuessState
  1842.           END
  1843.         END
  1844.       ELSE
  1845.         state := BlankState;
  1846.         IF x IN Mines THEN
  1847.           state := MineState
  1848.         END
  1849.       END;
  1850.       Intuition.DrawImage(FieldRPort,SquareImages[ORD(state)],xp  + CARDINAL(LeftFieldBorder),yp  + CARDINAL(TopFieldBorder));
  1851.       IF state = BlankState THEN
  1852.         sqv := Count(fMines,x,y);
  1853.         IF sqv > 0 THEN
  1854.           str[0] := CHR(ORD('0') + sqv);
  1855.           str[1] := 0C;
  1856.             xt := CARDINAL(LeftSquareText) + xp;
  1857.             yt := CARDINAL(TopSquareText) + yp;
  1858.             EasyText.DoWrite(SquareFont,FieldRPort,str,xt + 1,yt + 1,Pen1,-1,1);
  1859.             EasyText.DoWrite(SquareFont,FieldRPort,str,xt,yt,Pen2,-1,1);
  1860.         END
  1861.       END;
  1862.       INC(x);
  1863.       INC(xp,SquareWidth);
  1864.     UNTIL x = CARDINAL(FieldWidth);
  1865.   END;
  1866. END ShowARow;
  1867. *)
  1868.  
  1869. PROCEDURE ChangeFaceImage(ImageNum : CARDINAL);
  1870. VAR
  1871.     gadpos : INTEGER;
  1872. BEGIN
  1873.   FaceImage := dataPtr^.Images[ImageNum];
  1874.   IF NewGameGad^.GadgetRenderI # FaceImage THEN
  1875.     gadpos := Intuition.RemoveGadget(FieldWindow,NewGameGad);
  1876.     NewGameGad^.GadgetRenderI := FaceImage;
  1877.     gadpos := Intuition.AddGadget(FieldWindow,NewGameGad,gadpos);
  1878.   END;
  1879.   Intuition.RefreshGList(NewGameGad,FieldWindow,NIL,1);
  1880. END ChangeFaceImage;
  1881.  
  1882.  
  1883. PROCEDURE UncoveredAMine(x,y : CARDINAL);
  1884. VAR
  1885.     i,j : CARDINAL;
  1886.     cp : POINTER TO SquareState;
  1887. BEGIN
  1888.   EndGame(NoReStart);
  1889.   ChangeFaceImage(UnhappyImage);
  1890.   
  1891.   FOR j := 0 TO CARDINAL(FieldHeight) - 1 DO
  1892.     Chunky(j);
  1893.     cp := ADR(ChunkyBuf);
  1894.     FOR i := 0 TO CARDINAL(FieldWidth) - 1 DO
  1895.       CASE cp^ OF
  1896.       | UnknownState, BlankState, WonderState, GuessState :
  1897.       | MineState    :
  1898.             ShowSquare(i,j,MineState);
  1899.       | FoundMineState    :
  1900.           ShowSquare(i,j,FoundMineState);
  1901.       | BadGuessState    :
  1902.           ShowSquare(i,j,BadGuessState);
  1903.       END;
  1904.       INC(cp);
  1905.     END
  1906.   END;
  1907.   FlashDisplay(4);
  1908. END UncoveredAMine;
  1909.  
  1910.  
  1911. PROCEDURE ProcessStack();
  1912. VAR
  1913.     xi,yi : INTEGER;
  1914. BEGIN
  1915.   WHILE PopStack(xi,yi) DO
  1916.     IF CARDINAL(xi) IN FieldRows[CARDINAL(yi)].Mines THEN
  1917.       UncoveredAMine(xi,yi);
  1918.     ELSE
  1919.       DEC(NonMinesCovered);
  1920.       ShowASquare(xi,yi);
  1921.       IF LastSquareCount (*Count(fMines,xi,yi)*) = 0 THEN
  1922.         LookAround(xi,yi);
  1923.       END;
  1924.     END
  1925.   END;
  1926.   TestGameOver;
  1927. END ProcessStack;
  1928.  
  1929. PROCEDURE Guess(x,y : CARDINAL);
  1930. BEGIN
  1931.   IF INTEGER(x) >= 0 THEN
  1932.     WITH FieldRows[y] DO
  1933.       IF (x IN Covered) THEN
  1934.         IF x IN Guessed THEN
  1935.           EXCL(Guessed,x);
  1936.           IF ~Questions THEN
  1937.             EXCL(Wondered,x);
  1938.           END;
  1939.           DEC(GuessedMines);
  1940.           IF x IN Mines THEN
  1941.             DEC(GuessedRightMines)
  1942.           END;
  1943.         ELSIF x IN Wondered THEN
  1944.           EXCL(Wondered,x);
  1945.         ELSE
  1946.           INCL(Guessed,x);
  1947.           INCL(Wondered,x);
  1948.           INC(GuessedMines);
  1949.           IF x IN Mines THEN
  1950.             INC(GuessedRightMines)
  1951.           END
  1952.         END
  1953.       END;
  1954.     END;
  1955.     ShowASquare(x,y);
  1956.     UpdateMineCountDisplay;
  1957.     TestGameOver;
  1958.   END;
  1959. END Guess;
  1960.  
  1961.  
  1962.  
  1963. PROCEDURE RefreshDisplay(refresh : BOOLEAN);
  1964. VAR
  1965.     x,y : INTEGER;
  1966.     xp,yp : INTEGER;
  1967. BEGIN
  1968.   IF refresh THEN
  1969.     Intuition.BeginRefresh(FieldWindow);
  1970.     IF WindowSized THEN
  1971.       Intuition.EndRefresh(FieldWindow,TRUE);
  1972.     END;
  1973.   END;
  1974.   IF ~Shrunk THEN
  1975.     WITH FieldWindow^ DO
  1976.       DoFill(FieldRPort,FadePattern,1,Pen1,INTEGER(BorderLeft),INTEGER(BorderTop),Width - INTEGER(BorderRight) - 1,Height - INTEGER(BorderBottom) - 1);
  1977.     END;
  1978.  
  1979.     DoFill(FieldRPort,FadePattern,1,3,LeftFieldBorder,TopWindowBorder,RightFieldBorder,TopWindowBorder + TopWindowArea - 1);
  1980.  
  1981.     Pens.SetAPen(FieldRPort,Pen1);
  1982.     Pens.Move(FieldRPort,LeftFieldBorder,TopFieldBorder - 2);
  1983.     Pens.Draw(FieldRPort,LeftFieldBorder,TopWindowBorder);
  1984.     Pens.Draw(FieldRPort,RightFieldBorder,TopWindowBorder);
  1985.  
  1986.  
  1987.     Pens.SetAPen(FieldRPort,Pen2);
  1988.     Pens.Move(FieldRPort,RightFieldBorder, TopWindowBorder);
  1989.     Pens.Draw(FieldRPort,RightFieldBorder, TopFieldBorder - 2);
  1990.     Pens.Draw(FieldRPort,LeftFieldBorder,TopFieldBorder - 2);
  1991.  
  1992.     UpdateMineCountDisplay;
  1993.     UpdateTime;
  1994.     yp := TopFieldBorder;
  1995.  
  1996.     Pens.SetWrMsk(FieldRPort,{0..15});
  1997.     DoFill(FieldRPort,SquareImages[ORD(UnknownState)]^.ImageData,FillParam,3,LeftFieldBorder,TopFieldBorder,RightFieldBorder,TopFieldBorder + FieldWindowHeight - 1);
  1998.     Pens.SetWrMsk(FieldRPort,{0,1});
  1999.  
  2000.     y := FieldHeight;
  2001.     IF WaitingForNew THEN
  2002.       WHILE y > 0 DO
  2003.         DEC(y);
  2004.         WITH FieldRows[CARDINAL(y)] DO
  2005.           IF (Covered - Mines) # CoveredRow THEN
  2006.             ShowARow(y)
  2007.           END
  2008.         END;
  2009.       END;
  2010.     ELSE
  2011.       WHILE y > 0 DO
  2012.         DEC(y);
  2013.         IF FieldRows[CARDINAL(y)].Covered # CoveredRow THEN
  2014.           ShowARow(y)
  2015.         END;
  2016.       END;
  2017.     END;
  2018.     Restarting := FALSE;
  2019.   END;
  2020.   IF refresh & ~WindowSized THEN
  2021.     Intuition.EndRefresh(FieldWindow,TRUE);
  2022.   END;
  2023.   WindowSized := FALSE;
  2024.   Intuition.RefreshGList(NewGameGad,FieldWindow,NIL,1);
  2025. END RefreshDisplay;
  2026.  
  2027. PROCEDURE UnCover(x,y : CARDINAL);
  2028. VAR
  2029.     nx,ny : CARDINAL;
  2030. BEGIN
  2031.   WITH FieldRows[y] DO
  2032.     IF SafeIfMarked THEN
  2033.       IF (x IN Wondered) OR (x IN Guessed) THEN
  2034.         RETURN
  2035.       END;
  2036.     END;
  2037.     IF FirstHit THEN
  2038.       IF x IN Mines THEN
  2039.         IF ~SafeIfMarked THEN
  2040.           IF (x IN Wondered) & (x IN Guessed) THEN
  2041.             DEC(GuessedRightMines);
  2042.           END;
  2043.         END;
  2044.         ny := FastRandom.Random(FieldHeight);
  2045.         WHILE FieldRows[ny].Mines = CoveredRow DO
  2046.           ny := (ny + 1) MOD CARDINAL(FieldHeight);
  2047.         END;
  2048.         nx := FastRandom.Random(FieldWidth);
  2049.         WHILE nx IN FieldRows[ny].Mines DO
  2050.           nx := (nx + 1) MOD CARDINAL(FieldWidth);
  2051.         END;
  2052.         IF (nx IN FieldRows[ny].Wondered) & (nx IN FieldRows[ny].Guessed) THEN
  2053.           INC(GuessedRightMines);
  2054.         END;
  2055.         INCL(FieldRows[ny].Mines,nx);
  2056.         EXCL(Mines,x);
  2057.       END;
  2058.       StartTimer;
  2059.       FirstHit := FALSE
  2060.     END;
  2061.     Lastx := -1;
  2062.     IF ~SafeIfMarked THEN
  2063.       IF x IN Wondered THEN
  2064.         EXCL(Wondered,x);
  2065.         IF x IN Guessed THEN
  2066.           EXCL(Guessed,x);
  2067.           DEC(GuessedMines);
  2068.           IF x IN Mines THEN
  2069.             DEC(GuessedRightMines);
  2070.           END;
  2071.           UpdateMineCountDisplay;
  2072.         END;
  2073.       END;
  2074.     END;
  2075. (*
  2076.     IF x IN Mines THEN
  2077.       INCL(Guessed,x);
  2078.       EXCL(Wondered,x);
  2079.     END;
  2080. *)
  2081.   END;
  2082.   PushStack(x,y);
  2083.   ProcessStack;
  2084. END UnCover;
  2085.  
  2086. PROCEDURE SureSquare(x,y : CARDINAL);
  2087. BEGIN
  2088.   IF ~(x IN FieldRows[y].Covered) & (Count(fGuessed,x,y) = Count(fMines,x,y)) THEN
  2089.     LookAround(x,y);
  2090.     ProcessStack;
  2091.   END;
  2092. END SureSquare;
  2093.  
  2094. PROCEDURE ShowAround(x,y : INTEGER; image : Intuition.ImagePtr);
  2095. VAR
  2096.     xp,yp : INTEGER;
  2097.     mfr : MineFieldRow;
  2098.  
  2099.   PROCEDURE ShowOne;
  2100.   VAR
  2101.     sqr : Intuition.ImagePtr;
  2102.   BEGIN
  2103.     SETREG(2,x);
  2104.     IF (CARDINAL(REGISTER(2)) < CARDINAL(FieldWidth)) & (CARDINAL(y) < CARDINAL(FieldHeight)) THEN
  2105.       IF CARDINAL(REGISTER(2)) IN mfr.Covered THEN
  2106.         sqr := image;
  2107.         IF CARDINAL(REGISTER(2)) IN mfr.Wondered THEN
  2108.           sqr := SquareImages[WonderImage + CARDINAL(CARDINAL(REGISTER(2)) IN mfr.Guessed)];
  2109.         END;
  2110.         Intuition.DrawImage(FieldRPort,sqr,xp,yp);
  2111.       END;
  2112.     END
  2113.   END ShowOne;
  2114.   
  2115. BEGIN
  2116.   DEC(x);
  2117.   DEC(y);
  2118.   xp := x * SquareWidth + LeftFieldBorder;
  2119.   yp := y * SquareHeight + TopFieldBorder;
  2120.   
  2121.   mfr := FieldRows[y];
  2122.   ShowOne;
  2123.   INC(x);
  2124.   INC(xp,SquareWidth);
  2125.   ShowOne;
  2126.   INC(x);
  2127.   INC(xp,SquareWidth);
  2128.   ShowOne;
  2129.   INC(y);
  2130.   INC(yp,SquareHeight);
  2131.   mfr := FieldRows[y];
  2132.   ShowOne;
  2133.   DEC(x);
  2134.   DEC(xp,SquareWidth);
  2135.   ShowOne;
  2136.   DEC(x);
  2137.   DEC(xp,SquareWidth);
  2138.   ShowOne;
  2139.   INC(y);
  2140.   INC(yp,SquareHeight);
  2141.   mfr := FieldRows[y];
  2142.   ShowOne;
  2143.   INC(x);
  2144.   INC(xp,SquareWidth);
  2145.   ShowOne;
  2146.   INC(x);
  2147.   INC(xp,SquareWidth);
  2148.   ShowOne;
  2149. END ShowAround;
  2150.  
  2151.  
  2152. PROCEDURE ShowPos(x,y : INTEGER; OnBoard : BOOLEAN);
  2153. VAR
  2154.     str : ARRAY [0..11] OF CHAR;
  2155.     covered, b : BOOLEAN;
  2156.     xp,yp : INTEGER;
  2157.     square : Intuition.ImagePtr;
  2158. BEGIN
  2159.     IF (Lastx = x) & (Lasty = y) THEN RETURN END;
  2160.     IF Lastx >= 0 THEN
  2161.       CASE LastState OF
  2162.         NormalMove,MineMove :
  2163.           Blitter.BltBitMapRastPort(ADR(ClipBM),0,0,FieldRPort,Lastxp,Lastyp,SquareWidth,SquareHeight,CopyAtoD);
  2164.       | SafeMove :
  2165.           Blitter.BltBitMapRastPort(ADR(ClipBM),0,0,FieldRPort,Lastxp,Lastyp,SquareWidth3,SquareHeight3,CopyAtoD);
  2166.       ELSE
  2167.       END;
  2168.     END;
  2169.     IF OnBoard THEN
  2170.      xp := x * SquareWidth + LeftFieldBorder;
  2171.      yp := y * SquareHeight + TopFieldBorder;
  2172.      covered := (CARDINAL(x) IN FieldRows[CARDINAL(y)].Covered);
  2173.      CASE MovingState OF
  2174.      | NormalMove :
  2175.        IF covered THEN
  2176.          Blitter.ClipBlit(FieldRPort,xp,yp,ClipRPort,0,0,SquareWidth,SquareHeight,CopyAtoD);
  2177.          Intuition.DrawImage(FieldRPort,SquareImages[SureImage],xp,yp);
  2178.        ELSE
  2179.          x := -1
  2180.        END;
  2181.      | MineMove :
  2182.        IF covered THEN
  2183.          Blitter.ClipBlit(FieldRPort,xp,yp,ClipRPort,0,0,SquareWidth,SquareHeight,CopyAtoD);
  2184.          Intuition.DrawImage(FieldRPort,SquareImages[GuessImage],xp,yp);
  2185.        ELSE
  2186.          x := -1
  2187.        END;
  2188.      | SafeMove :
  2189.        DEC(xp,SquareWidth);
  2190.        DEC(yp,SquareHeight);
  2191.        Blitter.ClipBlit(FieldRPort,xp,yp,ClipRPort,0,0,SquareWidth3,SquareHeight3,CopyAtoD);
  2192.        ShowAround(x,y,SquareImages[SureImage]);
  2193.      ELSE
  2194.      END;
  2195.      Lastx := x;
  2196.      Lasty := y;
  2197.      Lastxp := xp;
  2198.      Lastyp := yp;
  2199.      LastState := MovingState;
  2200.    ELSE
  2201.      Lastx := -1
  2202.    END;
  2203. END ShowPos;
  2204.  
  2205. PROCEDURE MakeWindow() : Intuition.WindowPtr;
  2206. VAR
  2207.     nw : Intuition.NewWindowPtr;
  2208.     res : Intuition.WindowPtr;
  2209. BEGIN
  2210.   res := NIL;
  2211.   Storage.ALLOCATE(nw,SIZE(nw^));
  2212.   IF nw # NIL THEN
  2213.     WITH nw^ DO
  2214.       Width := 40 * SquareFont^.tfXSize;
  2215.       Height := 16 * SquareFont^.tfYSize;
  2216.       LeftEdge := FieldWindow^.LeftEdge + ((FieldWindow^.Width - Width) DIV 2);
  2217.       IF LeftEdge < 0 THEN LeftEdge := 0
  2218.       ELSIF (LeftEdge + Width) > FieldWindow^.WScreen^.Width THEN
  2219.         LeftEdge := FieldWindow^.WScreen^.Width - Width
  2220.       END;
  2221.       TopEdge := FieldWindow^.TopEdge + ((FieldWindow^.Height - Height) DIV 2);
  2222.       IF TopEdge < 0 THEN TopEdge := 0
  2223.       ELSIF (TopEdge + Height) > FieldWindow^.WScreen^.Height THEN
  2224.         TopEdge := FieldWindow^.WScreen^.Height - Height;
  2225.       END;
  2226.       Flags := Intuition.WindowFlagSet{Intuition.Activate, Intuition.NoCareRefresh};
  2227.       DetailPen := BYTE(Pen1);
  2228.       BlockPen := BYTE(Pen2);
  2229.       Type := Intuition.WBenchScreen;
  2230.     END;
  2231.     res := Intuition.OpenWindow(nw);
  2232.     Storage.DEALLOCATE(nw,0);
  2233.   END;
  2234.   RETURN res
  2235. END MakeWindow;
  2236.  
  2237. PROCEDURE myCloseWindow(win : Intuition.WindowPtr);
  2238. BEGIN
  2239.   win^.UserPort := NIL;
  2240.   Intuition.CloseWindow(win);
  2241. END myCloseWindow;
  2242.  
  2243. TYPE
  2244.     WaitMode = (waitWin,waitHigh,waitVal);
  2245.  
  2246. PROCEDURE WaitOnWindow(win : Intuition.WindowPtr; mode : WaitMode);
  2247. VAR
  2248.     port : Ports.MsgPortPtr;
  2249.     msg : Intuition.IntuiMessagePtr;
  2250. BEGIN
  2251.   port := FieldWindow^.UserPort;
  2252.   win^.UserPort := port;
  2253.   Intuition.ModifyIDCMP(win,Intuition.IDCMPFlagSet{Intuition.MouseButtons, Intuition.ActiveWindow, Intuition.GadgetUp});
  2254.   LOOP
  2255.     IF mode # waitWin THEN
  2256.       SETREG(0,Intuition.ActivateGadget(ADR(EntryGad^.Gad),win,NIL));
  2257.     END;
  2258.     LOOP
  2259.       msg := Ports.GetMsg(port);
  2260.       IF msg # NIL THEN
  2261.         EXIT
  2262.       END;
  2263.       msg := Ports.WaitPort(port);
  2264.     END;
  2265.     WITH msg^ DO
  2266.       IF  (IDCMPWindow = win) THEN
  2267.         IF  (Intuition.MouseButtons IN Class)
  2268.           & (Code = Intuition.SelectUp)
  2269.         THEN
  2270.           IF mode = waitWin THEN
  2271.             Ports.ReplyMsg(msg);
  2272.             EXIT
  2273.           END
  2274.         ELSIF (Intuition.GadgetUp IN Class) THEN
  2275.           Ports.ReplyMsg(msg);
  2276.           IF mode = waitHigh THEN
  2277.             WITH HighScores^.scores[Level] DO
  2278.               WITH EntryGad^.SI DO
  2279.                 NameLength := BYTE(NumChars);
  2280.                 IF Name # NIL THEN
  2281.                   Storage.DEALLOCATE(Name,0)
  2282.                 END;
  2283.                 Name := NIL;
  2284.                 IF NameLength # BYTE(0) THEN
  2285.                   Storage.ALLOCATE(Name,LONGINT(CARDINAL(NameLength) + 1));
  2286.                   IF Name # NIL THEN
  2287.   
  2288.                     Memory.CopyMem(Buffer,Name,CARDINAL(NameLength) + 1);
  2289.   
  2290.                   ELSE
  2291.                     NameLength := BYTE(0)
  2292.                   END;
  2293.                 END
  2294.               END
  2295.             END;
  2296.           END;
  2297.           EXIT
  2298.         END;
  2299.       ELSIF (IDCMPWindow = FieldWindow) THEN
  2300.         IF (Intuition.RefreshWindow IN Class) THEN
  2301.           RefreshDisplay(TRUE);
  2302.         END
  2303.       END;
  2304.     END;
  2305.     Ports.ReplyMsg(msg);
  2306.   END;
  2307.   IF mode # waitVal THEN
  2308.     myCloseWindow(win);
  2309.   END;
  2310. END WaitOnWindow;
  2311.  
  2312. CONST
  2313.     Spacer = "-----------";
  2314.  
  2315. TYPE
  2316.     EnterType = (eWidth,eHeight,eMines);
  2317.  
  2318. PROCEDURE ShowHighAbout(mode : HA);
  2319. VAR
  2320.     AboutWindow : Intuition.WindowPtr;
  2321.     line,linewidth,left,newval : INTEGER;
  2322.     rp : Rasters.RastPortPtr;
  2323.     Entering : EnterType;
  2324.     NewCustom : BOOLEAN;
  2325.  
  2326.    (*$STRING-*)
  2327.     PROCEDURE DoLine(str : ARRAY OF CHAR; length : INTEGER; colour : ColourNames);
  2328.     VAR
  2329.        l : INTEGER;
  2330.     BEGIN
  2331.       l := ((linewidth - (length * INTEGER(SquareFont^.tfXSize))) DIV 2) + left;
  2332.       EasyText.DoShadowWrite(SquareFont,rp,ADR(str),l, line,ColourPens[colour],Pen1,length);
  2333.      INC(line,INTEGER(SquareFont^.tfYSize));
  2334.     END DoLine;
  2335.  
  2336.   (*$STRING-*)
  2337.   PROCEDURE ShowScore(str : ARRAY OF CHAR; strl : CARDINAL; level : SkillLevel);
  2338.   VAR
  2339.     sp : STRPTR;
  2340.     l : INTEGER;
  2341.     buf : ARRAY [0..39] OF CHAR;
  2342.   BEGIN
  2343.     DoLine(str,strl,cnBlue);
  2344.     WITH HighScores^.scores[level] DO
  2345.       
  2346.       ConvNum(buf,Seconds);
  2347.       Memory.CopyMem(ADR(" by "),ADR(buf[4]),4);
  2348.       sp := ADR("Anonymous");
  2349.       l := 9;
  2350.       IF NameLength # BYTE(0) THEN
  2351.         sp := Name;
  2352.         l := CARDINAL(NameLength);
  2353.       END;
  2354.       Memory.CopyMem(sp,ADR(buf[8]),l);
  2355.       DoLine(buf,l+8,cnRed);
  2356.       DoLine(Spacer,11,cnGreen);
  2357.     END
  2358.   END ShowScore;
  2359.   
  2360.   PROCEDURE ConvertNumber(VAR s : ARRAY OF CHAR; index,v : CARDINAL) : CARDINAL;
  2361.   VAR
  2362.     sp : POINTER TO CHAR;
  2363.     dig : BOOLEAN;
  2364.     l,i,chars : CARDINAL;
  2365.   BEGIN
  2366.     dig := FALSE;
  2367.     sp := ADR(s) + ADDRESS(index);
  2368.     chars := 0;
  2369.     l := 1000;
  2370.     WHILE l > 0 DO
  2371.       i := (v DIV l);
  2372.       IF dig OR (i > 0) THEN
  2373.         sp^ := CHR(ORD("0") + i);
  2374.         INC(sp);
  2375.         INC(chars);
  2376.         dig := TRUE;
  2377.       END;
  2378.       v := v MOD l;
  2379.       l := l DIV 10;
  2380.     END;
  2381.     sp^ := 0C;
  2382.     RETURN chars
  2383.   END ConvertNumber;
  2384.   
  2385.     
  2386.   (*$STRING-*)
  2387.   PROCEDURE ShowValue(str : ARRAY OF CHAR; strl,val : CARDINAL);
  2388.   VAR
  2389.     buf : ARRAY [0..39] OF CHAR;
  2390.   BEGIN
  2391.     Memory.CopyMem(ADR(str),ADR(buf),strl);
  2392.     INC(strl,ConvertNumber(buf,strl,val));
  2393.     DoLine(buf,strl,cnBlue);
  2394.   END ShowValue;
  2395.  
  2396.   PROCEDURE SetVal(v:INTEGER);
  2397.   VAR
  2398.     sp : POINTER TO CHAR;
  2399.     l, i : INTEGER;
  2400.   BEGIN
  2401.     newval := v;
  2402.     WITH EntryGad^.SI DO
  2403.       LongInt := LONGINT(v);
  2404.       NumChars := ConvertNumber(Buffer^,0,v);
  2405.       BufferPos := NumChars;
  2406.     END;
  2407.   END SetVal;
  2408.  
  2409.   PROCEDURE ClearWin();
  2410.   VAR
  2411.       top, width, height : INTEGER;
  2412.   BEGIN
  2413.     WITH AboutWindow^ DO
  2414.       Pens.SetWrMsk(RPort,{0..15});
  2415.       left := INTEGER(BorderLeft);
  2416.       width := Width - INTEGER(BorderRight) - 1;
  2417.       top := INTEGER(BorderTop);
  2418.       height := Height - INTEGER(BorderBottom) - 1;
  2419.       DoFill(RPort,FadePattern,1,ColourPens[cnWhite], left, top, width, height);
  2420.       INC(left,16);
  2421.       INC(top,8);
  2422.       DEC(width,32);
  2423.       DEC(height,16);
  2424.       linewidth := width; (*Width - (INTEGER(BorderLeft) + INTEGER(BorderRight));*)
  2425.       Pens.SetAPen(RPort,0);
  2426.       Pens.RectFill(RPort,left, top, left + width, top + height);
  2427.       Pens.Move(RPort,left,top + height);
  2428.       Pens.SetAPen(RPort,Pen2);
  2429.       Pens.Draw(RPort,left,top);
  2430.       Pens.Draw(RPort,left + width,top);
  2431.       Pens.SetAPen(RPort,Pen1);
  2432.       Pens.Draw(RPort,left + width,top + height);
  2433.       Pens.Draw(RPort,left,top + height);
  2434.       line := INTEGER(BorderTop) + 14 (*INTEGER(CountFont^.tfYSize)*);
  2435.     END;
  2436.   END ClearWin;
  2437.   
  2438.  
  2439. BEGIN
  2440.   AboutWindow := MakeWindow();
  2441.   IF AboutWindow # NIL THEN
  2442.     rp := AboutWindow^.RPort;
  2443.     ClearWin;
  2444.     CASE mode OF
  2445.       modeAbout :
  2446.          DoLine(" ",1,cnWhite);
  2447.          DoLine("MineSweeper Version 2.7",23,cnWhite);
  2448.          DoLine("8th March 1994",14,cnWhite);
  2449.          DoLine(Spacer,11,cnGreen);
  2450.          DoLine("John Matthews",13,cnBlue);
  2451.          DoLine("4 Wadham Grove,",15,cnBlue);
  2452.          DoLine("Tawa,",5,cnBlue);
  2453.          DoLine("New Zealand",11,cnBlue);
  2454.          DoLine("Phone 64 4 232 7805",19,cnBlue);
  2455.          DoLine(Spacer,11,cnGreen);
  2456.          DoLine("Internet: probable unavailable",30,cnViolet);
  2457.          WaitOnWindow(AboutWindow, waitWin);
  2458.     | modeScores :
  2459.          DoLine("Best Times",10,cnWhite);
  2460.          DoLine(Spacer,11,cnGreen);
  2461.          ShowScore(BeginnerString,8,Beginner);
  2462.          ShowScore(IntermediateString,12,Intermediate);
  2463.          ShowScore(ExpertString,6,Expert);
  2464.          ShowScore(CustomString,6,Custom);
  2465.          WaitOnWindow(AboutWindow, waitWin);
  2466.     | modeGetName :
  2467.          IF InitEntryGad() THEN
  2468.            EXCL(EntryGad^.Gad.Activation,Intuition.LongInt);
  2469.            DoLine("Best Time !",11,cnWhite);
  2470.            DoLine(Spacer,11,cnGreen);
  2471.            ShowScore("Previous Best",13,Level);
  2472.            DoLine(" ",1,cnWhite);
  2473.            ShowValue("New Best ",9,NewHigh);
  2474.            DoLine(Spacer,11,cnGreen);
  2475.            DoLine("Enter your name...",18,cnPaleBlue);
  2476.            WITH EntryGad^.SI DO
  2477.              WITH HighScores^.scores[Level] DO
  2478.                NumChars := CARDINAL(NameLength);
  2479.                Seconds := NewHigh;
  2480.                DispPos := 0;
  2481.                UndoPos := 0;
  2482.                Memory.CopyMem(Name,Buffer,NumChars + 1);
  2483.              END
  2484.            END;
  2485.            SETREG(0,Intuition.AddGadget(AboutWindow,ADR(EntryGad^.Gad),-1));
  2486.            Intuition.RefreshGList(ADR(EntryGad^.Gad),AboutWindow,NIL,1);
  2487.          END;
  2488.          WaitOnWindow(AboutWindow, waitHigh);
  2489.     | modeGetCustom :
  2490.          IF InitEntryGad() THEN
  2491.            NewCustom := FALSE;
  2492.            INCL(EntryGad^.Gad.Activation,Intuition.LongInt);
  2493.            Entering := eWidth;
  2494.            LOOP
  2495.              DoLine(" ",1,cnWhite);
  2496.              DoLine("Custom Setup",12,cnWhite);
  2497.              DoLine(Spacer,11,cnGreen);
  2498.              ShowValue("Width   = ",10,customrec.Width);
  2499.              ShowValue("Height  = ",10,customrec.Height);
  2500.              ShowValue("# Mines = ",10,customrec.Mines);
  2501.              DoLine(Spacer,11,cnGreen);
  2502.              CASE Entering OF
  2503.              | eWidth  : DoLine("New Width   :",13,cnRed); SetVal(customrec.Width);
  2504.              | eHeight : DoLine("New Height  :",13,cnRed); SetVal(customrec.Height);
  2505.              | eMines  : DoLine("New # Mines :",13,cnRed); SetVal(customrec.Mines);
  2506.              END;
  2507.              EntryGad^.SI.LongInt := LONGINT(newval);
  2508.              SETREG(0,Intuition.AddGadget(AboutWindow,ADR(EntryGad^.Gad),-1));
  2509.              Intuition.RefreshGList(ADR(EntryGad^.Gad),AboutWindow,NIL,1);
  2510.              WaitOnWindow(AboutWindow, waitVal);
  2511.              SETREG(0,Intuition.RemoveGadget(AboutWindow,ADR(EntryGad^.Gad)));
  2512.              newval := INTEGER(EntryGad^.SI.LongInt);
  2513.              CASE Entering OF
  2514.              | eWidth :
  2515.                     IF (newval < MinFieldWidth) THEN newval := MinFieldWidth END;
  2516.                     IF (newval > MaxFieldWidth) THEN newval := MaxFieldWidth END;
  2517.                     NewCustom := NewCustom OR (customrec.Width # newval);
  2518.                     customrec.Width := newval;
  2519.              | eHeight :
  2520.                     IF (newval < MinFieldHeight) THEN newval := MinFieldHeight END;
  2521.                     IF (newval > MaxFieldHeight) THEN newval := MaxFieldHeight END;
  2522.                     NewCustom := NewCustom OR (customrec.Height # newval);
  2523.                     customrec.Height := newval;
  2524.                  | eMines :
  2525.                    IF (newval < MinMines) THEN newval := MinMines END;
  2526.                    IF (newval > MaxMines) THEN newval := MaxMines END;
  2527.                    NewCustom := NewCustom OR (customrec.Mines # newval);
  2528.                    customrec.Mines := newval;
  2529.                    myCloseWindow(AboutWindow);
  2530.                    IF NewCustom THEN
  2531.                      WITH HighScores^.scores[Custom] DO
  2532.                        Seconds := 9999;
  2533.                        NameLength := BYTE(0);
  2534.                        IF Name # NIL THEN
  2535.                          Storage.DEALLOCATE(Name,0);
  2536.                          Name := NIL;
  2537.                        END
  2538.                      END
  2539.                    END;
  2540.                    RETURN
  2541.                  END;
  2542.                  INC(Entering);
  2543.                  ClearWin();
  2544.               END;
  2545.             END;
  2546.     END;
  2547.   END;
  2548. END ShowHighAbout;
  2549.  
  2550. PROCEDURE TestGameOver();
  2551. VAR
  2552.     f : LONGBITSET;
  2553.     i,j : INTEGER;
  2554.     r : BOOLEAN;
  2555. BEGIN
  2556.     IF ~WaitingForNew THEN
  2557.       CASE CompleteMethod OF
  2558.       | AllMinesFound :
  2559.           r := (GuessedRightMines # NumMines)
  2560.       | AllNonMinesFound :
  2561.           r := (NonMinesCovered > 0)
  2562.       | AllSquaresFound :
  2563.           r := (GuessedRightMines # NumMines) OR (NonMinesCovered > 0)
  2564.       | EitherCompletion :
  2565.           r := ~((GuessedRightMines = NumMines) OR (NonMinesCovered = 0))
  2566.       END;
  2567.       IF r THEN RETURN END;
  2568.      EndGame(NoReStart);
  2569.      ChangeFaceImage(SunGlassesImage);
  2570.      FlashDisplay(2);
  2571.      FOR i := 0 TO FieldHeight - 1 DO
  2572.       WITH FieldRows[i] DO
  2573.         f := (Mines * Covered);
  2574.         Guessed := Guessed + f;
  2575.         Wondered := Wondered + f;
  2576.         FOR j := 0 TO FieldWidth - 1 DO
  2577.           IF CARDINAL(j) IN f THEN
  2578.             ShowSquare(j,i,GuessState)
  2579.           END
  2580.         END;
  2581.       END;
  2582.      END;
  2583.      IF Seconds < HighScores^.scores[Level].Seconds THEN
  2584.        NewHigh := Seconds;
  2585.        ShowHighAbout(modeGetName);
  2586.      END;
  2587.    END
  2588. END TestGameOver;
  2589.  
  2590.  
  2591. PROCEDURE ShrinkWindow();
  2592. VAR
  2593.     gadpos : INTEGER;
  2594.     bool : BOOLEAN;
  2595. BEGIN
  2596.   IF ~Shrunk THEN
  2597.     Shrunk := TRUE;
  2598.     StopTimer;
  2599.     LastFieldWidth := 0;
  2600.     gadpos := Intuition.RemoveGadget(FieldWindow,NewGameGad);
  2601.     WITH NewGameGad^ DO
  2602.       LeftEdge := LeftFieldBorder;
  2603.       TopEdge := TopWindowBorder;
  2604.       bool := MySizeWindow(LeftEdge + RightWindowBorder + Width - 1,
  2605.                            TopEdge + BottomWindowBorder + Height - 1);
  2606.     END;
  2607.     gadpos := Intuition.AddGadget(FieldWindow,NewGameGad,-1);
  2608.     WITH FieldWindow^ DO
  2609.       DoFill(FieldRPort,FadePattern,1,Pen1,INTEGER(BorderLeft),INTEGER(BorderTop),Width - INTEGER(BorderRight) - 1,Height - INTEGER(BorderBottom) - 1);
  2610.     END;
  2611.     Intuition.RefreshGadgets(NewGameGad,FieldWindow,NIL);
  2612.   END
  2613. END ShrinkWindow;
  2614.  
  2615.  
  2616. PROCEDURE ProcessMenus(menunum : CARDINAL) : BOOLEAN;
  2617. VAR
  2618.     itemnum : CARDINAL;
  2619.     mItem : Intuition.MenuItemPtr;
  2620.     newsize,newgame : BOOLEAN;
  2621.     sl : SkillLevel;
  2622. BEGIN
  2623.   newgame := FALSE;
  2624.   newsize := FALSE;
  2625.   WHILE menunum # Intuition.MenuNULL DO
  2626.     itemnum := Intuition.ITEMNUM(menunum);
  2627.     mItem := Intuition.ItemAddress(menu,menunum);
  2628.     IF Intuition.MENUNUM(menunum) = 0 THEN
  2629.       CASE VAL(MenuVals,itemnum) OF
  2630.         mNewGame :
  2631.           newgame := TRUE;
  2632.       | mBeginner .. mCustom :
  2633.           sl := VAL(SkillLevel,itemnum - ORD(mBeginner));
  2634.           newsize := TRUE;
  2635.           IF sl = Custom THEN
  2636.             ShowHighAbout(modeGetCustom)
  2637.           END;
  2638.       | mQuestions : Questions := Intuition.Checked IN mItem^.Flags
  2639.       | mCursor :
  2640.           MovingAllowed := (Intuition.SUBNUM(menunum) = 0);
  2641.       | mSafe : SafeIfMarked := Intuition.Checked IN mItem^.Flags
  2642.       | mScores : ShowHighAbout(modeScores);
  2643.       | mAbout : ShowHighAbout(modeAbout);
  2644.       | mShrink :
  2645.          IF Shrunk THEN
  2646.            IF ~CreateFieldWindow() THEN
  2647.              RETURN FALSE
  2648.            END;
  2649.          ELSE
  2650.            ShrinkWindow;
  2651.          END;
  2652.       | mQuit : QuitNow := TRUE; RETURN TRUE
  2653. (*      | mTest : ShowStates;*)
  2654.       END;
  2655.     ELSE
  2656.       CompleteMethod := VAL(CompleteMethodType,itemnum)
  2657.     END;
  2658.     menunum := mItem^.NextSelect
  2659.   END;
  2660.   IF newsize THEN
  2661.     SetSize(sl);
  2662.     RETURN TRUE
  2663.   END;
  2664.   IF newgame THEN
  2665.     RETURN TRUE
  2666.   END;
  2667.   RETURN FALSE
  2668. END ProcessMenus;
  2669.  
  2670.  
  2671. PROCEDURE PlayGame() : BOOLEAN;
  2672. VAR
  2673.     port : Ports.MsgPortPtr;
  2674.     msgcopy : Intuition.IntuiMessage;
  2675.     OnBoard, Breaking : BOOLEAN;
  2676.  
  2677.   PROCEDURE AWaitEvent;
  2678.   VAR
  2679.     msg : Intuition.IntuiMessagePtr;
  2680.     sigs : Tasks.SignalSet;
  2681.   BEGIN
  2682.     sigs := Tasks.SetSignal(Tasks.SignalSet{},WaitBits);
  2683.     LOOP
  2684.       IF DOS.SIGBreakC IN sigs THEN
  2685.         Breaking := TRUE;
  2686.         RETURN
  2687.       END;
  2688.       IF CARDINAL(CountBit) IN sigs THEN
  2689.         UpdateTime;
  2690.       END;
  2691.       sigs := Tasks.SignalSet{};
  2692.       msg := Ports.GetMsg(port);
  2693.       IF msg # NIL THEN
  2694.         IF msg^.IDCMPWindow = FieldWindow THEN
  2695.           msgcopy := msg^;
  2696.           Ports.ReplyMsg(msg);
  2697.           OnBoard := Transform(msgcopy.MouseX,msgcopy.MouseY);
  2698.           IF OnBoard & ~WaitingForNew THEN
  2699.             INCL(FieldWindow^.Flags,Intuition.RMBTrap)
  2700.           ELSE
  2701.             EXCL(FieldWindow^.Flags,Intuition.RMBTrap)
  2702.           END;
  2703.           RETURN
  2704.         END;
  2705.         Ports.ReplyMsg(msg);
  2706.       ELSE
  2707.         sigs := Tasks.Wait(WaitBits);
  2708.       END;
  2709.     END
  2710.   END AWaitEvent;
  2711.  
  2712.   PROCEDURE ChangeMoveState( newstate : MovingStateType; AllowedStarting : MovingStateSet; MouseChange : BOOLEAN);
  2713.   VAR
  2714.       x,y : INTEGER;
  2715.   BEGIN
  2716.     WITH msgcopy DO
  2717.       IF MovingState = NoMove THEN
  2718.         IF OnBoard & (newstate # NoMove) THEN
  2719.           Intuition.DrawImage(FieldRPort,dataPtr^.Images[AstonishedImage],SmileX, SmileY);
  2720.           FromMouse := MouseChange;
  2721.           MovingState := newstate;
  2722.           ShowPos(MouseX, MouseY, OnBoard);
  2723.         END
  2724.       ELSE
  2725.         x := Lastx;
  2726.         y := Lasty;
  2727.         ShowPos(-1,-1,FALSE);
  2728.         IF (newstate = NoMove)
  2729.             & (MovingState IN AllowedStarting)
  2730.             & (FromMouse = MouseChange)
  2731.         THEN
  2732.           IF OnBoard THEN
  2733.             CASE MovingState OF
  2734.             | NoMove     :
  2735.             | NormalMove : UnCover(x,y);
  2736.             | SafeMove   : SureSquare(x,y);
  2737.             | MineMove   : Guess(x,y);
  2738.             END;
  2739.           END;
  2740.         END;
  2741.         MovingState := NoMove;
  2742.         Intuition.DrawImage(FieldRPort,FaceImage,SmileX, SmileY);
  2743.       END
  2744.     END;
  2745.   END ChangeMoveState;
  2746.   
  2747.  
  2748. BEGIN
  2749.    ChangeFaceImage(SmileyImage);
  2750.    EmptyStack;
  2751.     MovingState := NoMove;
  2752.    WaitBits := Tasks.SignalSet{DOS.SIGBreakC,CARDINAL(CountBit),CARDINAL(WindowBit)};
  2753.     Seconds := 0;
  2754.     UpdateTime;
  2755.     port := FieldWindow^.UserPort;
  2756.     FirstHit := TRUE;
  2757.     Lastx := -1;
  2758.     Lasty := 0;
  2759.     LastState := NoMove;
  2760.     Breaking := FALSE;
  2761.     RefreshDisplay(FALSE);
  2762.     LOOP
  2763.        AWaitEvent;
  2764.        IF Breaking THEN
  2765.          StopTimer;
  2766.          RETURN TRUE
  2767.        END;
  2768.       WITH msgcopy DO
  2769.          IF Intuition.CloseWindowFlag IN Class THEN
  2770.              StopTimer;
  2771.             RETURN TRUE
  2772.          ELSIF Intuition.MenuPick IN Class THEN
  2773.             IF ProcessMenus(Code) THEN
  2774.               EndGame(DoReStart);
  2775.               RETURN FALSE
  2776.             END;
  2777.          ELSIF Intuition.NewSize IN Class THEN
  2778.             RefreshDisplay(TRUE);
  2779.          ELSIF Intuition.RefreshWindow IN Class THEN
  2780.             RefreshDisplay(TRUE);
  2781.          ELSIF Intuition.MouseButtons IN Class THEN
  2782.             IF (Code = Intuition.MenuUp) THEN
  2783.               ChangeMoveState(NoMove,MovingStateSet{SafeMove,MineMove},TRUE);
  2784.             ELSIF (Code = Intuition.MenuDown) THEN
  2785.               IF CARDINAL(MouseX) IN FieldRows[MouseY].Covered THEN
  2786.                 ChangeMoveState(MineMove,MovingStateSet{},TRUE);
  2787.               ELSE
  2788.                 ChangeMoveState(SafeMove,MovingStateSet{},TRUE);
  2789.               END;
  2790.             ELSIF (Code = Intuition.SelectUp) THEN
  2791.               ChangeMoveState(NoMove,MovingStateSet{NormalMove},TRUE);
  2792.             ELSIF (Code = Intuition.SelectDown) & OnBoard THEN
  2793.               ChangeMoveState(NormalMove,MovingStateSet{},TRUE);
  2794.             END;
  2795.          ELSIF Intuition.GadgetUp IN Class THEN
  2796.            ChangeMoveState(NoMove,MovingStateSet{MineMove,SafeMove,NormalMove},TRUE);
  2797.            IF Shrunk THEN
  2798.              IF ~CreateFieldWindow() THEN
  2799.                RETURN FALSE
  2800.              END;
  2801.            ELSE
  2802.              EndGame(DoReStart);
  2803.              RETURN FALSE
  2804.            END;
  2805.          ELSIF Intuition.GadgetDown IN Class THEN
  2806.              ChangeMoveState(NoMove,MovingStateSet{MineMove,SafeMove,NormalMove},TRUE);
  2807.          ELSIF Intuition.RawKey IN Class THEN
  2808.            IF BITSET(InputEvents.IECodeUpPrefix) * BITSET(Code) # BITSET{} THEN
  2809.              (* key up *)
  2810.              ChangeMoveState(NoMove,MovingStateSet{SafeMove,MineMove,NormalMove},FALSE);
  2811.              IF ~WaitingForNew THEN
  2812.                INCL(FieldWindow^.Flags,Intuition.RMBTrap)
  2813.              END
  2814.            ELSE
  2815.              IF OnBoard & (MovingState = NoMove) THEN
  2816.                CASE Console.RawToASCII(msgcopy) OF
  2817.                | 'm','M','g','G' :
  2818.                   ChangeMoveState(MineMove,MovingStateSet{},FALSE);
  2819.                | 'u','U','1' :
  2820.                   ChangeMoveState(NormalMove,MovingStateSet{},FALSE);
  2821.                | 'l','L','a','A' :
  2822.                   ChangeMoveState(SafeMove,MovingStateSet{},FALSE);
  2823.                | '2' :
  2824.                  IF CARDINAL(MouseX) IN FieldRows[MouseY].Covered THEN
  2825.                    ChangeMoveState(MineMove,MovingStateSet{},FALSE);
  2826.                  ELSE
  2827.                    ChangeMoveState(SafeMove,MovingStateSet{},FALSE);
  2828.                  END;
  2829.                | 'p','P' :
  2830.                  OnBoard := FALSE;
  2831.                  ChangeMoveState(NoMove,MovingStateSet{SafeMove,MineMove,NormalMove},FALSE);
  2832.                  IF Shrunk THEN
  2833.                    IF ~CreateFieldWindow() THEN
  2834.                      RETURN FALSE
  2835.                    END;
  2836.                  ELSE
  2837.                    ShrinkWindow;
  2838.                  END;
  2839. (***TestLookAround+
  2840.                | 't' : TestLookAround(MouseX,MouseY);
  2841. *TestLookAround-*)
  2842.                ELSE
  2843.                  EXCL(FieldWindow^.Flags,Intuition.RMBTrap)
  2844.                END
  2845.              END
  2846.            END
  2847.          ELSIF MovingAllowed & (Intuition.MouseMove IN Class) THEN
  2848.            IF (MovingState # NoMove) THEN
  2849.              ShowPos(MouseX, MouseY, OnBoard)
  2850.            END;
  2851.          END
  2852.       END
  2853.     END;
  2854.     RETURN FALSE
  2855. END PlayGame;
  2856.  
  2857. PROCEDURE CloseDisplay();
  2858. VAR
  2859.     port : Ports.MsgPortPtr;
  2860.     msg : ADDRESS;
  2861.     cm : Views.ColorMapPtr;
  2862.     cn : ColourNames;
  2863. BEGIN
  2864.     port := FieldWindow^.UserPort;
  2865.     Interrupts.Forbid;
  2866.     LOOP
  2867.         msg := Ports.GetMsg(port);
  2868.         IF msg = NIL THEN EXIT END;
  2869.         Ports.ReplyMsg(msg);
  2870.     END;
  2871.     cm := FieldWindow^.WScreen^.VPort.ColorMap;
  2872.    FOR cn := MIN(ColourNames) TO MAX(ColourNames) DO
  2873.      IF cn IN ObtainedPens THEN
  2874.        Pens.ReleasePen(cm,LONGCARD(ColourPens[cn]))
  2875.      END
  2876.    END;
  2877.    ObtainedPens := ColourNameSet{};
  2878.    
  2879.     Intuition.CloseWindow(FieldWindow);
  2880.     Interrupts.Permit;
  2881. END CloseDisplay;
  2882.  
  2883. PROCEDURE SetUpTimer() : BOOLEAN;
  2884. VAR
  2885.     sigs : Tasks.SignalSet;
  2886.     oldpri : INTEGER;
  2887. BEGIN
  2888.   TimerAcks := Tasks.SignalSet{CARDINAL(TimerAckBit)};
  2889.   oldpri := Tasks.SetTaskPri(MainTask,0);
  2890.   TimerTask := TaskUtils.CreateTask(ADR(TaskName),1,TimerProc,4096);
  2891.   sigs := Tasks.Wait(TimerAcks);
  2892.   RETURN ~TimerError;
  2893. END SetUpTimer;
  2894.  
  2895. PROCEDURE GetHighScores();
  2896. VAR
  2897.     fh : DOS.FileHandle;
  2898.     err : LONGINT;
  2899.     i : CARDINAL;
  2900.     l : SkillLevel;
  2901.     b : BYTE;
  2902.  
  2903.   PROCEDURE ReadScore(level : SkillLevel) : BOOLEAN;
  2904.   BEGIN
  2905.     WITH HighScores^.scores[level] DO
  2906.       Name := NIL;
  2907.       IF CARDINAL(NameLength) > 0 THEN
  2908.         err := -1;
  2909.         Storage.ALLOCATE(Name,LONGINT(CARDINAL(NameLength)) + 1);
  2910.         IF Name # NIL THEN
  2911.           err := DOS.Read(fh,Name,LONGINT(CARDINAL(NameLength)));
  2912.         END;
  2913.         IF err # LONGINT(CARDINAL(NameLength)) THEN
  2914.           RETURN FALSE
  2915.         END;
  2916.       END;
  2917.     END;
  2918.     RETURN TRUE
  2919.   END ReadScore;
  2920.   
  2921.  
  2922. BEGIN
  2923.   CompleteMethod := AllSquaresFound;
  2924.   Storage.ALLOCATE(HighScores, SIZE(HighScores^));
  2925.   IF HighScores = NIL THEN HALT END;
  2926.   FOR l := Beginner TO Custom DO
  2927.     WITH HighScores^.scores[l] DO
  2928.       Seconds := 9999;
  2929.     END;
  2930.   END;
  2931.   WITH HighScores^ DO
  2932.     DefLevel := Beginner;
  2933.     DefQuestions := TRUE;
  2934.   END;
  2935.   WITH customrec DO
  2936.     version := 1;
  2937.     Width := 8;
  2938.     Height := 8;
  2939.     Mines := 10;
  2940.   END;
  2941.   fh := DOS.Open(ADR(MineScores),DOS.ModeOldFile);
  2942.   IF fh # NIL THEN
  2943.     err := DOS.Read(fh,HighScores,SIZE(HighScores^) - SIZE(Score));
  2944.     IF err # SIZE(HighScores^) - SIZE(Score) THEN
  2945.       SETREG(0,DOS.Close(fh));
  2946.       RETURN
  2947.     END;
  2948.     FOR l := Beginner TO Expert DO
  2949.       IF ~ReadScore(l) THEN
  2950.         SETREG(0,DOS.Close(fh));
  2951.         RETURN
  2952.       END;
  2953.     END;
  2954.     err := DOS.Read(fh,ADR(HighScores^.scores[Custom]),SIZE(Score));
  2955.     HighScores^.scores[Custom].Name := NIL;
  2956.     IF (err # SIZE(Score)) OR ~ReadScore(Custom) THEN
  2957.       HighScores^.scores[Custom].NameLength := BYTE(0);
  2958.       SETREG(0,DOS.Close(fh));
  2959.       RETURN
  2960.     END;
  2961.     err :=DOS.Read(fh,ADR(customrec),SIZE(customrec));
  2962.     IF (err # SIZE(customrec)) THEN
  2963.       HighScores^.scores[Custom].NameLength := BYTE(0);
  2964.       SETREG(0,DOS.Close(fh));
  2965.       RETURN
  2966.     END;
  2967.     err := DOS.Read(fh,ADR(b),SIZE(b));
  2968.     IF (err = SIZE(b)) THEN
  2969.       CompleteMethod := VAL(CompleteMethodType,b)
  2970.     END;
  2971.     err := DOS.Read(fh,ADR(b),SIZE(b));
  2972.     IF (err = SIZE(b)) THEN
  2973.       MovingAllowed := (b = BYTE(1));
  2974.     END;
  2975.     err := DOS.Read(fh,ADR(b),SIZE(b));
  2976.     IF (err = SIZE(b)) THEN
  2977.       SafeIfMarked := (b = BYTE(1));
  2978.     END;
  2979.   END;
  2980.   SETREG(0,DOS.Close(fh));
  2981. END GetHighScores;
  2982.  
  2983. PROCEDURE SaveHighScores();
  2984. VAR
  2985.     fh : DOS.FileHandle;
  2986.     err : LONGINT;
  2987.     i : CARDINAL;
  2988.     l : SkillLevel;
  2989.     b : BYTE;
  2990.  
  2991.   PROCEDURE WriteScore(level : SkillLevel) : BOOLEAN;
  2992.   BEGIN
  2993.     WITH HighScores^.scores[level] DO
  2994.       IF CARDINAL(NameLength) > 0 THEN
  2995.         err := -1;
  2996.         err := DOS.Write(fh,Name,LONGINT(CARDINAL(NameLength)));
  2997.         IF err # LONGINT(CARDINAL(NameLength)) THEN
  2998.           RETURN FALSE
  2999.         END;
  3000.       END;
  3001.     END;
  3002.     RETURN TRUE;
  3003.   END WriteScore;
  3004.   
  3005.  
  3006. BEGIN
  3007.   IF HighScores = NIL THEN RETURN END;
  3008.   WITH HighScores^ DO
  3009.     InitX := FieldWindow^.LeftEdge;
  3010.     InitY := FieldWindow^.TopEdge;
  3011.     DefLevel := Level;
  3012.     DefQuestions := Questions;
  3013.   END;
  3014.   fh := DOS.Open(ADR(MineScores),DOS.ModeNewFile);
  3015.   IF fh # NIL THEN
  3016.     err := DOS.Write(fh,HighScores,SIZE(HighScores^) - SIZE(Score));
  3017.     IF err # (SIZE(HighScores^) - SIZE(Score)) THEN
  3018.       SETREG(0,DOS.Close(fh));
  3019.       RETURN
  3020.     END;
  3021.     FOR l := Beginner TO Expert DO
  3022.       IF ~WriteScore(l) THEN
  3023.         SETREG(0,DOS.Close(fh));
  3024.         RETURN
  3025.       END;
  3026.     END;
  3027.     err := DOS.Write(fh,ADR(HighScores^.scores[Custom]),SIZE(Score));
  3028.     IF (err # SIZE(Score)) OR ~WriteScore(Custom) THEN
  3029.       SETREG(0,DOS.Close(fh));
  3030.       RETURN
  3031.     END;
  3032.     customrec.version := HighScoreVersion;
  3033.     IF (DOS.Write(fh,ADR(customrec),SIZE(customrec)) = SIZE(customrec)) THEN
  3034.       b := BYTE(CompleteMethod);
  3035.       err := DOS.Write(fh,ADR(b),SIZE(b));
  3036.       IF err = SIZE(b) THEN
  3037.         b := BYTE(0);
  3038.         IF MovingAllowed THEN
  3039.           b := BYTE(1);
  3040.         END;
  3041.         err := DOS.Write(fh,ADR(b),SIZE(b));
  3042.         IF err = SIZE(b) THEN
  3043.           b := BYTE(0);
  3044.           IF SafeIfMarked THEN
  3045.             b := BYTE(1);
  3046.           END;
  3047.           err := DOS.Write(fh,ADR(b),SIZE(b));
  3048.         END;
  3049.       END
  3050.     END;
  3051.   END;
  3052.   SETREG(0,DOS.Close(fh));
  3053. END SaveHighScores;
  3054.  
  3055. PROCEDURE GetWindowSizes() : BOOLEAN;
  3056. VAR
  3057.     nw : Intuition.NewWindowPtr;
  3058.     win : Intuition.WindowPtr;
  3059.     vp : Views.ViewPortPtr;
  3060. BEGIN
  3061.   V36 := (RunTime.ExecVersion > 35);
  3062.   Storage.ALLOCATE(nw,SIZE(nw^));
  3063.   IF nw = NIL THEN RETURN FALSE END;
  3064.   WITH nw^ DO
  3065.     Width := 10;
  3066.     Height := 10;
  3067.     Flags := Intuition.WindowFlagSet{Intuition.BackDrop};
  3068.     Type := Intuition.WBenchScreen;
  3069.     Title := ADR(MineSweeperName);
  3070.   END;
  3071.   win := Intuition.OpenWindow(nw);
  3072.   Storage.DEALLOCATE(nw,0);
  3073.   IF win = NIL THEN
  3074.     RETURN FALSE
  3075.   END;
  3076.   vp := Intuition.ViewPortAddress(win);
  3077.   Laced := Views.Lace IN vp^.Modes;
  3078.   IF Laced THEN
  3079.     SquareHeight := 16;
  3080.     Memory.CopyMem(ADR(dataPtr^.Images[FirstImage]),ADR(SquareImages),SIZE(SquareImages));
  3081.     FillParam := -4;
  3082.   ELSE
  3083.     SquareHeight := 8;
  3084.     Memory.CopyMem(ADR(dataPtr^.Images[LastImage + 1]),ADR(SquareImages),SIZE(SquareImages));
  3085.     FillParam := -3;
  3086.   END;
  3087.   SquareHeight3 := SquareHeight * 3;
  3088.   WITH win^ DO
  3089.     LeftFieldBorder := INTEGER(BorderLeft) + 16 - (INTEGER(BorderLeft) MOD 16);
  3090.     TopWindowBorder := INTEGER(BorderTop) + 1;
  3091.     RightWindowBorder := INTEGER(BorderRight) + 16 - (INTEGER(BorderRight) MOD 16);
  3092.     BottomWindowBorder := INTEGER(BorderBottom) + 16 - (INTEGER(BorderBottom) MOD 16);
  3093.     TopFieldBorder := TopWindowBorder + TopWindowArea;
  3094.     INC(TopFieldBorder,SquareHeight - (TopFieldBorder MOD SquareHeight));
  3095.   END;
  3096.   Intuition.CloseWindow(win);
  3097.   RETURN TRUE
  3098. END GetWindowSizes;
  3099.  
  3100.  
  3101. BEGIN
  3102.   ObtainedPens := ColourNameSet{};
  3103.   CT := ADR(ChunkyTable);
  3104. (*  Storage.ALLOCATE(StackBuffer,SIZE(SquareRecord) * MaxStackDepth);*)
  3105.   StackBuffer := ADR(RealStackBuffer);
  3106. (*StackCheck+
  3107.   StackDepthReached := 0;
  3108. *StackCheck-*)
  3109.   Shrunk := FALSE;
  3110.   EntryGad := NIL;
  3111.   MovingAllowed := TRUE;
  3112.   SafeIfMarked := FALSE;
  3113.   IF dataPtr = NIL THEN HALT END;
  3114.   FadePattern := dataPtr^.Images[FadePat]^.ImageData;
  3115.   IF ~GetWindowSizes() THEN HALT END;
  3116.   GetHighScores;
  3117.   WITH HighScores^ DO
  3118.     Questions := DefQuestions;
  3119.     SetSize(DefLevel);
  3120.   END;
  3121.   OpenFonts;
  3122.   CreateMenus;
  3123.   MainTask := Tasks.FindTask(Tasks.CurrentTask);
  3124.   MainProcess := DOSProcess.ProcessPtr(MainTask);
  3125.   OLDprWindow := MainProcess^.prWindowPtr;
  3126.   QuitNow := FALSE;
  3127.   TimerIsGoing := FALSE;
  3128.   TimerError := FALSE;
  3129.   TimerAckBit := Tasks.AllocSignal(Tasks.AnySignal);
  3130.   CountBit := Tasks.AllocSignal(Tasks.AnySignal);
  3131.   IF (TimerAckBit # Tasks.NoSignals) & (CountBit # Tasks.NoSignals) THEN
  3132.     IF SetUpTimer() THEN
  3133.       FieldWindow := NIL;
  3134.       REPEAT
  3135.         QuitNow := (~CreateFieldWindow()) OR PlayGame() OR QuitNow;
  3136.       UNTIL QuitNow;
  3137.       StopTimer;
  3138.       MainProcess^.prWindowPtr := OLDprWindow;
  3139.       SaveHighScores;
  3140.       CloseDisplay;
  3141.       (*ShowFields*)
  3142.     END
  3143.   END;
  3144.   IF (TimerAckBit # Tasks.NoSignals) THEN
  3145.     Tasks.FreeSignal(TimerAckBit);
  3146.   END;
  3147.   IF (CountBit # Tasks.NoSignals) THEN
  3148.     Tasks.FreeSignal(CountBit);
  3149.   END;
  3150. (*    EasyText.EasyCloseFont(CountFont);*)
  3151.   EasyText.EasyCloseFont(SquareFont);
  3152. (*StackCheck+
  3153.   TermOut.WriteString("MAX Stack Depth = ");
  3154.   TermOut.WriteCard(StackDepthReached,1);
  3155.   TermOut.WriteLn;
  3156. *StackCheck-*)
  3157. END MineSweeper.
  3158.